javax.imageio.IIOException: невозможно прочитать входной файл! на банке netbeans [дубликат]

Вот универсальная функция для преобразования либо объекта timedelta, либо обычного номера (в виде секунд или минут и т. д.) в красиво отформатированную строку. Я взял фантастический ответ mpounsett по дублированному вопросу, сделал его немного более гибким, улучшенным читабельностью и добавленной документацией.

Вы найдете, что это самый гибкий ответ здесь, поскольку он позволяет вам:

  1. Настроить формат строки «на лету» вместо того, чтобы быть жестко закодированным .
  2. Оставьте определенные промежутки времени без проблем (см. примеры ниже).

Функция:

from string import Formatter
from datetime import timedelta

def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
    """Convert a datetime.timedelta object or a regular number to a custom-
    formatted string, just like the stftime() method does for datetime.datetime
    objects.

    The fmt argument allows custom formatting to be specified.  Fields can 
    include seconds, minutes, hours, days, and weeks.  Each field is optional.

    Some examples:
        '{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
        '{W}w {D}d {H}:{M:02}:{S:02}'     --> '4w 5d 8:04:02'
        '{D:2}d {H:2}:{M:02}:{S:02}'      --> ' 5d  8:04:02'
        '{H}h {S}s'                       --> '72h 800s'

    The inputtype argument allows tdelta to be a regular number instead of the  
    default, which is a datetime.timedelta object.  Valid inputtype strings: 
        's', 'seconds', 
        'm', 'minutes', 
        'h', 'hours', 
        'd', 'days', 
        'w', 'weeks'
    """

    # Convert tdelta to integer seconds.
    if inputtype == 'timedelta':
        remainder = int(tdelta.total_seconds())
    elif inputtype in ['s', 'seconds']:
        remainder = int(tdelta)
    elif inputtype in ['m', 'minutes']:
        remainder = int(tdelta)*60
    elif inputtype in ['h', 'hours']:
        remainder = int(tdelta)*3600
    elif inputtype in ['d', 'days']:
        remainder = int(tdelta)*86400
    elif inputtype in ['w', 'weeks']:
        remainder = int(tdelta)*604800

    f = Formatter()
    desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
    possible_fields = ('W', 'D', 'H', 'M', 'S')
    constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
    values = {}
    for field in possible_fields:
        if field in desired_fields and field in constants:
            values[field], remainder = divmod(remainder, constants[field])
    return f.format(fmt, **values)

Демоверсия:

>>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340)

>>> print strfdelta(td)
02d 03h 05m 08s

>>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}')
2d 3:05:08

>>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}')
 2d  3:05:08

>>> print strfdelta(td, '{H}h {S}s')
51h 308s

>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s

>>> print strfdelta(620, '{H}:{M:02}', 'm')
10:20

>>> print strfdelta(49, '{D}d {H}h', 'h')
2d 1h

131
задан Andrew Thompson 14 June 2018 в 14:24
поделиться

9 ответов

Вместо того, чтобы пытаться адресовать ресурс в качестве файла , просто попросите ClassLoader вернуть InputStream для ресурса вместо getResourceAsStream :

InputStream in = getClass().getResourceAsStream("/file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

Пока ресурс file.txt доступен в пути к классам, этот подход будет работать одинаково независимо от того, находится ли ресурс file.txt в файле classes/ ] или внутри jar.

URI is not hierarchical происходит потому, что URI для ресурса в файле jar будет выглядеть примерно так: file:/example.jar!/file.txt. Вы не можете прочитать записи в файле jar (файл zip), как будто это был обычный старый файл .

Это объясняется ответами на:

237
ответ дан Drew MacInnis 17 August 2018 в 12:21
поделиться
  • 1
    Спасибо, это было очень полезно, и код работает отлично, но у меня есть одна проблема, мне нужно определить, существует ли InputStream (например, File.exists()), поэтому моя игра может определить, использовать ли файл по умолчанию или нет. Благодарю. – PrinceCJC 5 December 2013 в 17:23
  • 2
    О, и BTW, причина getClass().getResource("**/folder**/file.txt") заставила его работать, потому что у меня была эта папка в том же каталоге, что и моя банка :). – PrinceCJC 5 December 2013 в 17:33
  • 3
    getResourceAsStream возвращает значение null, если ресурс не существует, так что может быть вашим & quot; существует & quot; контрольная работа. – Drew MacInnis 5 December 2013 в 21:05
  • 4
    BTW, у вас есть опечатка: это должен быть BufferedReader, а не BufferredReader (обратите внимание на дополнительные «r» в дальнейшем) – mailmindlin 6 September 2014 в 06:56
  • 5
    И, конечно же ... не забудьте закрыть inputStream и BufferedReader – Noremac 15 May 2015 в 13:38

После многократного поиска в Java единственное решение, которое, похоже, работает для меня, - это вручную прочитать файл jar, если вы не находитесь в среде разработки (IDE):

/** @return The root folder or jar file that the class loader loaded from */
public static final File getClasspathFile() {
    return new File(YourMainClass.class.getProtectionDomain().getCodeSource().getLocation().getFile());
}

/** @param resource The path to the resource
 * @return An InputStream containing the resource's contents, or
 *         <b><code>null</code></b> if the resource does not exist */
public static final InputStream getResourceAsStream(String resource) {
    resource = resource.startsWith("/") ? resource : "/" + resource;
    if(getClasspathFile().isDirectory()) {//Development environment:
        return YourMainClass.class.getResourceAsStream(resource);
    }
    final String res = resource;//Jar or exe:
    return AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
        @SuppressWarnings("resource")
        @Override
        public InputStream run() {
            try {
                final JarFile jar = new JarFile(getClasspathFile());
                String resource = res.startsWith("/") ? res.substring(1) : res;
                if(resource.endsWith("/")) {//Directory; list direct contents:(Mimics normal getResourceAsStream("someFolder/") behaviour)
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    Enumeration<JarEntry> entries = jar.entries();
                    while(entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        if(entry.getName().startsWith(resource) && entry.getName().length() > resource.length()) {
                            String name = entry.getName().substring(resource.length());
                            if(name.contains("/") ? (name.endsWith("/") && (name.indexOf("/") == name.lastIndexOf("/"))) : true) {//If it's a folder, we don't want the children's folders, only the parent folder's children!
                                name = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
                                baos.write(name.getBytes(StandardCharsets.UTF_8));
                                baos.write('\r');
                                baos.write('\n');
                            }
                        }
                    }
                    jar.close();
                    return new ByteArrayInputStream(baos.toByteArray());
                }
                JarEntry entry = jar.getJarEntry(resource);
                InputStream in = entry != null ? jar.getInputStream(entry) : null;
                if(in == null) {
                    jar.close();
                    return in;
                }
                final InputStream stream = in;//Don't manage 'jar' with try-with-resources or close jar until the
                return new InputStream() {//returned stream is closed(closing the jar closes all associated InputStreams):
                    @Override
                    public int read() throws IOException {
                        return stream.read();
                    }

                    @Override
                    public int read(byte b[]) throws IOException {
                        return stream.read(b);
                    }

                    @Override
                    public int read(byte b[], int off, int len) throws IOException {
                        return stream.read(b, off, len);
                    }

                    @Override
                    public long skip(long n) throws IOException {
                        return stream.skip(n);
                    }

                    @Override
                    public int available() throws IOException {
                        return stream.available();
                    }

                    @Override
                    public void close() throws IOException {
                        try {
                            jar.close();
                        } catch(IOException ignored) {
                        }
                        stream.close();
                    }

                    @Override
                    public synchronized void mark(int readlimit) {
                        stream.mark(readlimit);
                    }

                    @Override
                    public synchronized void reset() throws IOException {
                        stream.reset();
                    }

                    @Override
                    public boolean markSupported() {
                        return stream.markSupported();
                    }
                };
            } catch(Throwable e) {
                e.printStackTrace();
                return null;
            }
        }
    });
}

Примечание: приведенный выше код, похоже, работает правильно для файлов jar, если он находится в основном классе. Я не уверен, почему.

0
ответ дан Brian_Entei 17 August 2018 в 12:21
поделиться

Вы также можете просто использовать java.nio. Вот пример того, как slurp в тексте из файла в resourcePath в пути к классам:

new String(Files.readAllBytes(Paths.get(getClass().getResource(resourcePath).toURI())))
1
ответ дан Community 17 August 2018 в 12:21
поделиться
  • 1
  • 2
    Это действительно не удастся, если ресурс находится внутри файла jar. Мне любопытно, знает ли кто-нибудь о надлежащем способе чтения из банки с использованием класса Files, как показано в этом примере, то есть не используется inputstream. – George Curington 5 May 2016 в 00:44

Чтобы получить доступ к файлу в банке, у вас есть две возможности:

  • Поместите файл в структуру каталогов, соответствующую вашему имени пакета (после извлечения файла .jar он должен находиться в том же каталоге, что и .class file), затем обращайтесь к нему с помощью getClass().getResourceAsStream("file.txt")
  • Поместите файл в корневой каталог (после извлечения файла .jar, он должен быть в корневом каталоге), затем обращайтесь к нему с помощью Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

Первый вариант может не работать, если jar используется в качестве плагина.

9
ответ дан Juozas Kontvainis 17 August 2018 в 12:21
поделиться

У меня была эта проблема раньше, и я сделал резервный способ загрузки. В основном первый способ работы внутри .jar-файла и второго способа работает внутри eclipse или другой среды IDE.

public class MyClass {

    public static InputStream accessFile() {
        String resource = "my-file-located-in-resources.txt";

        // this is the path within the jar file
        InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
        if (input == null) {
            // this is how we load file within editor (eg eclipse)
            input = MyClass.class.getClassLoader().getResourceAsStream(resource);
        }

        return input;
    }
}
1
ответ дан MForm 17 August 2018 в 12:21
поделиться

До сих пор (декабрь 2017 г.) это единственное найденное решение, которое работает как внутри, так и снаружи IDE.

Использовать PathMatchingResourcePatternResolver

Примечание: он работает также в spring-boot

. В этом примере я читаю некоторые файлы, расположенные в src / main / resources / my_folder:

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
0
ответ дан Naor Bar 17 August 2018 в 12:21
поделиться

Если вы хотите читать как файл, я считаю, что все еще есть аналогичное решение:

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("file/test.xml").getFile());
6
ответ дан pablo.vix 17 August 2018 в 12:21
поделиться
  • 1
    URL.getFile () не конвертирует URL-адрес в имя файла. Он возвращает часть URL-адреса после хоста, при этом все процентные кодировки остаются нетронутыми, поэтому, если в пути содержатся любые символы, отличные от ASCII, или любые символы ASCII, которые не разрешены в URL-адресах (включая пробелы), результат не будет именем существующего файла , даже если URL-адрес является file: URL-адресом. – VGR 5 March 2016 в 19:07
  • 2
    это не работает внутри, как только программа строится на банке – Akshay Kasar 20 September 2017 в 12:42
  • 3
    Не работает из jar, если вы не конвертируете в строку и сначала сохраняете ее локально. – smoosh911 9 August 2018 в 16:55

Убедитесь, что вы работаете с правильным разделителем. Я заменил все / на относительный путь с помощью File.separator. Это отлично работало в среде IDE, однако не работало в JAR сборки.

1
ответ дан Petterson 17 August 2018 в 12:21
поделиться

Если вы используете Spring, вы можете использовать следующий метод для чтения файла из src / main / resources:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;

public String readFile() {

    StringBuilder result = new StringBuilder("");
    ClassPathResource resource = new ClassPathResource("filename.txt");

    try (InputStream inputStream = resource.getInputStream()) {

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;

        while ((line = bufferedReader.readLine()) != null) {
            result.append(line);
        }
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return result.toString();
}
-1
ответ дан Sujan M. 17 August 2018 в 12:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: