diff --git a/source/net/filebot/HistorySpooler.java b/source/net/filebot/HistorySpooler.java index 598986a5..142df972 100644 --- a/source/net/filebot/HistorySpooler.java +++ b/source/net/filebot/HistorySpooler.java @@ -4,10 +4,10 @@ import static net.filebot.Settings.*; import java.io.File; import java.io.IOException; -import java.io.RandomAccessFile; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -50,17 +50,12 @@ public final class HistorySpooler { return new History(sessionHistory.sequences()); } - RandomAccessFile f = new RandomAccessFile(persistentHistoryFile, "rw"); - FileChannel channel = f.getChannel(); - FileLock lock = channel.lock(); - try { - History history = History.importHistory(new CloseShieldInputStream(Channels.newInputStream(channel))); // keep JAXB from closing the stream - history.addAll(sessionHistory.sequences()); - return history; - } finally { - lock.release(); - channel.close(); - f.close(); + try (FileChannel channel = FileChannel.open(persistentHistoryFile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { + try (FileLock lock = channel.lock()) { + History history = History.importHistory(new CloseShieldInputStream(Channels.newInputStream(channel))); // keep JAXB from closing the stream + history.addAll(sessionHistory.sequences()); + return history; + } } } @@ -70,35 +65,29 @@ public final class HistorySpooler { } try { - if (persistentHistoryFile.length() <= 0) { - persistentHistoryFile.createNewFile(); - } - RandomAccessFile f = new RandomAccessFile(persistentHistoryFile, "rw"); - FileChannel channel = f.getChannel(); - FileLock lock = channel.lock(); - try { - History history = new History(); - if (persistentHistoryFile.length() > 0) { - try { - channel.position(0); // rewind - history = History.importHistory(new CloseShieldInputStream(Channels.newInputStream(channel))); // keep JAXB from closing the stream - } catch (Exception e) { - Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Failed to load rename history.", e); + try (FileChannel channel = FileChannel.open(persistentHistoryFile.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { + try (FileLock lock = channel.lock()) { + History history = new History(); + + // load existing history from previous sessions + if (channel.size() > 0) { + try { + channel.position(0); + history = History.importHistory(new CloseShieldInputStream(Channels.newInputStream(channel))); // keep JAXB from closing the stream + } catch (Exception e) { + Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Failed to load rename history.", e); + } } + + // write new combined history + history.addAll(sessionHistory.sequences()); + + channel.position(0); + History.exportHistory(history, new CloseShieldOutputStream(Channels.newOutputStream(channel))); // keep JAXB from closing the stream + + sessionHistory.clear(); + persistentHistoryTotalSize = history.totalSize(); } - history.addAll(sessionHistory.sequences()); - - channel.position(0); - History.exportHistory(history, new CloseShieldOutputStream(Channels.newOutputStream(channel))); // keep JAXB from closing the stream - - sessionHistory.clear(); - persistentHistoryTotalSize = history.totalSize(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - lock.release(); - channel.close(); - f.close(); } } catch (Exception e) { Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Failed to write rename history.", e); diff --git a/source/net/filebot/Main.java b/source/net/filebot/Main.java index fe45ec82..25bf2c51 100644 --- a/source/net/filebot/Main.java +++ b/source/net/filebot/Main.java @@ -14,10 +14,8 @@ import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.nio.ByteBuffer; @@ -25,6 +23,7 @@ import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.charset.Charset; +import java.nio.file.StandardOpenOption; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; @@ -123,7 +122,7 @@ public class Main { } // open file channel and lock - FileChannel logChannel = new FileOutputStream(logFile, true).getChannel(); + FileChannel logChannel = FileChannel.open(logFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND); if (args.logLock) { System.out.println("Locking " + logFile); logChannel.lock(); @@ -446,8 +445,7 @@ public class Main { final File lockFile = new File(cache, ".lock"); boolean isNewCache = !lockFile.exists(); - final RandomAccessFile handle = new RandomAccessFile(lockFile, "rw"); - final FileChannel channel = handle.getChannel(); + final FileChannel channel = FileChannel.open(lockFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE); final FileLock lock = channel.tryLock(); if (lock != null) { @@ -499,7 +497,7 @@ public class Main { // ignore, shutting down anyway } try { - handle.close(); + channel.close(); } catch (Exception e) { // ignore, shutting down anyway } @@ -511,7 +509,7 @@ public class Main { } // try next lock file - handle.close(); + channel.close(); } } catch (Exception e) { Logger.getLogger(Main.class.getName()).log(Level.WARNING, e.toString(), e); diff --git a/source/net/filebot/ui/transfer/ByteBufferTransferable.java b/source/net/filebot/ui/transfer/ByteBufferTransferable.java index 7b643299..bbc817b3 100644 --- a/source/net/filebot/ui/transfer/ByteBufferTransferable.java +++ b/source/net/filebot/ui/transfer/ByteBufferTransferable.java @@ -1,7 +1,5 @@ - package net.filebot.ui.transfer; - import static net.filebot.Settings.*; import static net.filebot.util.FileUtilities.*; @@ -9,29 +7,25 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import net.filebot.util.FileUtilities; import net.filebot.util.TemporaryFolder; - public class ByteBufferTransferable implements Transferable { - + protected final Map vfs; - + private FileTransferable transferable; - public ByteBufferTransferable(Map vfs) { this.vfs = vfs; } - @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { @@ -41,62 +35,52 @@ public class ByteBufferTransferable implements Transferable { if (transferable == null) { transferable = createFileTransferable(); } - + return transferable.getTransferData(flavor); } catch (IOException e) { throw new RuntimeException(e); } } - + throw new UnsupportedFlavorException(flavor); } - protected FileTransferable createFileTransferable() throws IOException { // remove invalid characters from file name List files = new ArrayList(); - + for (Entry entry : vfs.entrySet()) { String name = entry.getKey(); ByteBuffer data = entry.getValue().duplicate(); - + // write temporary file files.add(createTemporaryFile(name, data)); } - + return new FileTransferable(files); } - protected File createTemporaryFile(String name, ByteBuffer data) throws IOException { // remove invalid characters from file name String validFileName = validateFileName(name); - + // create new temporary file in TEMP/APP_NAME [UUID]/dnd File temporaryFile = TemporaryFolder.getFolder(getApplicationName()).subFolder("dnd").createFile(validFileName); - + // write data to file - FileChannel fileChannel = new FileOutputStream(temporaryFile).getChannel(); - - try { - fileChannel.write(data); - } finally { - fileChannel.close(); - } - + FileUtilities.writeFile(data, temporaryFile); + return temporaryFile; } - @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { DataFlavor.javaFileListFlavor, FileTransferable.uriListFlavor }; } - @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return FileTransferable.isFileListFlavor(flavor); } - + } diff --git a/source/net/filebot/util/FileUtilities.java b/source/net/filebot/util/FileUtilities.java index d70379ee..c6f678ab 100644 --- a/source/net/filebot/util/FileUtilities.java +++ b/source/net/filebot/util/FileUtilities.java @@ -6,7 +6,6 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; @@ -23,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; @@ -204,7 +204,7 @@ public final class FileUtilities { } public static File writeFile(ByteBuffer data, File destination) throws IOException { - try (FileOutputStream stream = new FileOutputStream(destination); FileChannel channel = stream.getChannel()) { + try (FileChannel channel = FileChannel.open(destination.toPath(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) { channel.write(data); } return destination; diff --git a/source/net/filebot/web/OpenSubtitlesHasher.java b/source/net/filebot/web/OpenSubtitlesHasher.java index 7ceeefe4..eca3c255 100644 --- a/source/net/filebot/web/OpenSubtitlesHasher.java +++ b/source/net/filebot/web/OpenSubtitlesHasher.java @@ -1,7 +1,5 @@ - package net.filebot.web; - import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; @@ -12,38 +10,30 @@ import java.nio.ByteOrder; import java.nio.LongBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; - +import java.nio.file.StandardOpenOption; /** - * Hash code is based on Media Player Classic. In natural language it calculates: size + 64bit - * checksum of the first and last 64k (even if they overlap because the file is smaller than - * 128k). + * Hash code is based on Media Player Classic. In natural language it calculates: size + 64bit checksum of the first and last 64k (even if they overlap because the file is smaller than 128k). */ public final class OpenSubtitlesHasher { - + /** * Size of the chunks that will be hashed in bytes (64 KB) */ public static final int HASH_CHUNK_SIZE = 64 * 1024; - public static String computeHashNIO(File file) throws IOException { long size = file.length(); long chunkSizeForFile = Math.min(HASH_CHUNK_SIZE, size); - - FileChannel fileChannel = new FileInputStream(file).getChannel(); - - try { - long head = computeHashForChunk(fileChannel.map(MapMode.READ_ONLY, 0, chunkSizeForFile)); - long tail = computeHashForChunk(fileChannel.map(MapMode.READ_ONLY, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile)); - + + try (FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.READ)) { + long head = computeHashForChunk(channel.map(MapMode.READ_ONLY, 0, chunkSizeForFile)); + long tail = computeHashForChunk(channel.map(MapMode.READ_ONLY, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile)); + return String.format("%016x", size + head + tail); - } finally { - fileChannel.close(); } } - - + public static String computeHash(File file) throws IOException { FileInputStream in = new FileInputStream(file); try { @@ -52,44 +42,43 @@ public final class OpenSubtitlesHasher { in.close(); } } - public static String computeHash(InputStream stream, long length) throws IOException { int chunkSizeForFile = (int) Math.min(HASH_CHUNK_SIZE, length); - + // buffer that will contain the head and the tail chunk, chunks will overlap if length is smaller than two chunks byte[] chunkBytes = new byte[(int) Math.min(2 * HASH_CHUNK_SIZE, length)]; - + DataInputStream in = new DataInputStream(stream); - + // first chunk in.readFully(chunkBytes, 0, chunkSizeForFile); - + long position = chunkSizeForFile; long tailChunkPosition = length - chunkSizeForFile; - + // seek to position of the tail chunk, or not at all if length is smaller than two chunks - while (position < tailChunkPosition && (position += in.skip(tailChunkPosition - position)) >= 0); - + while (position < tailChunkPosition && (position += in.skip(tailChunkPosition - position)) >= 0) { + } + // second chunk, or the rest of the data if length is smaller than two chunks in.readFully(chunkBytes, chunkSizeForFile, chunkBytes.length - chunkSizeForFile); - + long head = computeHashForChunk(ByteBuffer.wrap(chunkBytes, 0, chunkSizeForFile)); long tail = computeHashForChunk(ByteBuffer.wrap(chunkBytes, chunkBytes.length - chunkSizeForFile, chunkSizeForFile)); - + return String.format("%016x", length + head + tail); } - private static long computeHashForChunk(ByteBuffer buffer) { LongBuffer longBuffer = buffer.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer(); long hash = 0; - + while (longBuffer.hasRemaining()) { hash += longBuffer.get(); } - + return hash; } - + }