2015-12-11 4 views
1

Мне нужно разобрать содержимое файла epub, и я пытаюсь понять, что было бы самым эффективным способом сделать это. Файл epub может содержать изображения, много текста и иногда видео. Должен ли я искать FileInputStream или FileReader?Могу ли я использовать FileReader для чтения файла, содержащего изображения и видео (скажем, файл epub) и текста, и предлагается ли это сделать в отношении производительности.

+1

Ясно 'FileInputStream' если ваш формат не чистый текст. – Mena

ответ

2

Поскольку epub использует структуру архива ZIP, я бы предложил обработать его как таковой. Найдите небольшой фрагмент, ниже которого будет отображаться содержимое файла epub.

Map<String, String> env = new HashMap<>(); 
env.put("create", "true"); 

Path path = Paths.get("foobar.epub"); 
URI uri = URI.create("jar:" + path.toUri()); 
FileSystem zipFs = FileSystems.newFileSystem(uri, env); 
Path root = zipFs.getPath("/"); 
Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 
    @Override 
    public FileVisitResult visitFile(Path file, 
      BasicFileAttributes attrs) throws IOException { 
     print(file); 
     return FileVisitResult.CONTINUE; 
    } 

    @Override 
    public FileVisitResult preVisitDirectory(Path dir, 
      BasicFileAttributes attrs) throws IOException { 
     print(dir); 
     return FileVisitResult.CONTINUE; 
    } 

    private void print(Path file) throws IOException { 
     Date lastModifiedTime = new Date(Files.getLastModifiedTime(file).toMillis()); 
     System.out.printf("%td.%<tm.%<tY %<tH:%<tM:%<tS %9d %s\n", 
       lastModifiedTime, Files.size(file), file); 
    } 
}); 

выход образец

01.01.1970 00:59:59   0 /META-INF/ 
11.02.2015 16:33:44  244 /META-INF/container.xml 
11.02.2015 16:33:44  3437 /logo.jpg 
... 

редактировать Если вы хотите, чтобы извлечь файлы, основанные на их имена вы могли бы сделать это, как показано в этом фрагменте кода для метода visitFile(...).

public FileVisitResult visitFile(Path file, 
    BasicFileAttributes attrs) throws IOException { 
    // if the filename inside the epub end with "*logo.jpg" 
    if (file.endsWith("logo.jpg")) { 
     // extract the file in directory /tmp/ 
     Files.copy(file, Paths.get("/tmp/", 
      file.getFileName().toString())); 
    } 
    return FileVisitResult.CONTINUE; 
} 

В зависимости от того, как вы хотите обрабатывать файлы внутри EPUB вы также можете иметь взгляд на ZipInputStream.

try (ZipInputStream in = new ZipInputStream(new FileInputStream("foobar.epub"))) { 
    for (ZipEntry entry = in.getNextEntry(); entry != null; 
     entry = in.getNextEntry()) { 
     System.out.printf("%td.%<tm.%<tY %<tH:%<tM:%<tS %9d %s\n", 
       new Date(entry.getTime()), entry.getSize(), entry.getName()); 
     if (entry.getName().endsWith("logo.jpg")) { 
      try (FileOutputStream out = new FileOutputStream(entry.getName())) { 
       // process the file 
      } 
     } 
    } 
} 

выход образец

11.02.2013 16:33:44  244 META-INF/container.xml 
11.02.2013 16:33:44  3437 logo.jpg 
+0

Это хороший подход. Еще одно дополнение: метод 'visitFile' должен решить, использовать ли InputStream или Reader для чтения содержимого каждого файла. –

+0

Спасибо SubOptimal за всеобъемлющее предложение. @Little Santi, я не понял комментарий о visitFile, определяющем подход к чтению содержимого каждого файла. – Zooter

+0

@Zooter Я имел в виду, что каждый файл должен быть прочитан либо как текст (через API-интерфейсы Reader), либо как двоичный (через Stream API). И это деление должно быть принято в методе 'visitFile'. –

0

Самый простой способ читать весь файл в байтах (и то, что вы хотите, если это не обычный текст) будет использовать java.nio.file.Files класс:

byte[] content = Files.readAllBytes(Paths.get("example.epub")); 

Преимущества этого метода:

  • меньше код = код становится более читаемым и имеет меньше возможностей для ошибок
  • java заботится об открытии и закрытии файла

Edit:

Для того, чтобы прочитать файл очень быстро вы можете использовать java.nio, а также. На этот раз java.nio.channels.FileChannel:

import java.io.FileInputStream; 
import java.nio.MappedByteBuffer; 
import java.nio.channels.FileChannel; 

// Load the file 
FileChannel c = new FileInputStream("example.epub").getChannel(); 
MappedByteBuffer byteBuffer = c.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); 

// Process the data 
buffer.get(myByte, 1120, 50); 

// when finished 
c.close(); 

Это не будет читать весь файл в память, но и создает ссылку на файл и читает (буфера) только части вы пытаетесь получить доступ. Он также распознает изменения в файле и всегда возвращает последний контент.

+1

Спасибо Деннис за ответ. Но в документации говорится, что этот метод лучше обрабатывает мелкие файлы и не идеален для его использования для больших файлов. Мне нужно прочитать файлы epub, которые могут идти до 50 МБ или более. – Zooter

+0

да, это зависит от того, как будет работать ваш код позже, я не буду называть 50 МБ более крупным файлом, но это зависит от того, на каком компьютере он работает (особенно в памяти). Конечно, вы можете обрабатывать файл шаг за шагом, я добавлю пример –

+0

Как указано здесь: http://stackoverflow.com/a/9094629/2546444 пример, показанный в редакции, должен иметь возможность подготовить 2 ГБ в младше 10 миллисекунды, которые должны быть достаточно быстрыми для вас;) –