This is the 8th day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021.
This article focuses on the use of files in NIO to become, primarily, FileChannel.
Common FileChannel operations
1.1 get FileChannel
There is a file called text.txt with the following contents:
abcdef
Copy the code
You cannot open A FileChannel directly; you must obtain a FileChannel via FileInputStream, FileOutputStream, or RandomAccessFile, all of which have the getChannel method
1.1.1 Obtaining the file through FileInputStream
public static void main(String[] args) throws Exception {
// Get a channel using FileInputStream
FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\P50\\Desktop\\text.txt"));
FileChannel channel1 = fileInputStream.getChannel();
ByteBuffer buffer= ByteBuffer.allocate(10);
//channel1.write(buffer);
channel1.read(buffer);
buffer.flip();
System.out.println((print(buffer)));
}
static String print(ByteBuffer b) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < b.limit(); i++) {
stringBuilder.append((char) b.get(i));
}
return stringBuilder.toString();
}
Copy the code
Results:
abcdef
Copy the code
Channels obtained by FileInputStream are only readable. If the write write method is used, an exception will be thrown:
Exception in thread "main" java.nio.channels.NonWritableChannelException
at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:201)
at com.cloud.bssp.nio.FileChannel.GetFileChannel.main(GetFileChannel.java:21)
Copy the code
1.1.2 Obtaining the file through FileOutputStream
public static void main(String[] args) throws Exception {
// Use FileOutputStream to get a channel
FileOutputStream fileOutputStream = new FileOutputStream(new File("C:\\Users\\P50\\Desktop\\text.txt"),true);
FileChannel channel2 = fileOutputStream.getChannel();
ByteBuffer buffer= ByteBuffer.allocate(10);
buffer.put(StandardCharsets.UTF_8.encode("helloworld"));
buffer.flip();
channel2.write(buffer);
}
static String print(ByteBuffer b) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < b.limit(); i++) {
stringBuilder.append((char) b.get(i));
}
return stringBuilder.toString();
}
Copy the code
The file is written to. Note that the FileOutputStream property append, if true, appends, otherwise overwrites. The append used in this article.
abcdefhelloworld
Copy the code
Channels obtained via FileOutputStream can only be written. If the read method is used, an exception will be thrown:
Exception in thread "main" java.nio.channels.NonReadableChannelException
at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:149)
at com.cloud.bssp.nio.FileChannel.GetFileChannel.main(GetFileChannel.java:28)
Copy the code
1.1.3 Obtain through RandomAccessFile
public static void main(String[] args) throws Exception {
// Get the channel using RandomAccessFile
RandomAccessFile file = new RandomAccessFile("C:\\Users\\P50\\Desktop\\text.txt"."rw");
FileChannel channel3 = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(15);
// Read the contents of the file into buffer
channel3.read(buffer);
buffer.flip();
System.out.println(print(buffer));
// Switch to write mode and empty buffer
buffer.clear();
// Write helloWorld to the file
buffer.put(StandardCharsets.UTF_8.encode("helloworld"));
buffer.flip();
channel3.write(buffer);
}
// Switch to write mode and empty buffer
buffer.clear();
// Write helloWorld to the file
buffer.put(StandardCharsets.UTF_8.encode("helloworld"));
buffer.flip();
channel3.write(buffer);
Copy the code
Result: One byte is missing because the buffer I specified is only 15, and the document is 16, which is read only once.
abcdefhelloworl
Copy the code
The content of the document is modified as follows, concatenating the content read by the channel with the new content added
abcdefhelloworlhelloworld
Copy the code
Whether we can read and write through RandomAccessFile depends on the read and write mode at the time RandomAccessFile was constructed, specifying the RW (read and write mode).
1.2 Read and Write
1.2.1 read
As shown in the previous fetch example, an int is returned, the ByteBuffer is filled with data read from a channel, and the return value is -1, indicating that the end of the file has been reached.
int readBytes = channel.read(buffer);
Copy the code
Still using the first example above, -1 is returned if the document is empty
int read = channel1.read(buffer);
System.out.println(read);
Copy the code
- 1Copy the code
1.2.2 write
The example in the previous section showed how to write data to a buffer using the write method to write to a channel, but the correct way to write data should look like this:
while(buffer.hasRemaining()) {
channel.write(buffer);
}
Copy the code
HasRemaining () is a method of buffer that determines whether position is less than limit. If it is, it returns true, indicating that buffer still has unread data.
Write is called in the while because the write method does not guarantee that all the contents of the buffer will be written to the channel at once.
1.2.3 Forcible Write
For performance reasons, the operating system caches data instead of writing it to disk immediately. You can call the channel.force(true) method to write the file contents and metadata (information such as the file’s permissions) to disk immediately.
public abstract void force(boolean metaData) throws IOException;
Copy the code
1.3 shut down
None of the code we’ve written above actually closes streams and channels, which can cause serious problems in production.
A channel must be closed, but a close() method calling FileInputStream, FileOutputStream, or RandomAccessFile indirectly calls a channel’s close method.
Take a look at FileInputStream’s close method:
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
Copy the code
1.4 Position of the FileChannel
Get current location
long pos = channel.position();
Copy the code
Set current Position
longnewPos = ... ; channel.position(newPos);Copy the code
Obtain file channel as follows:
Helloworld RandomAccessFile file = new RandomAccessFile("C:\ Users\ P50\ Desktop\ text.txt", "rw"); FileChannel channel = file.getChannel();Copy the code
Print the position of different Settings:
// Print position, 0 if not read
System.out.println(channel.position());
// Read the length of the file
ByteBuffer buffer = ByteBuffer.allocate(10);
channel.read(buffer);
System.out.println(channel.position());
// Set the length after the position
FileChannel position = channel.position(5);
System.out.println(position.position());
Copy the code
Results:
0 to 10 5Copy the code
1.5 Obtaining the File size
channel.size();
Copy the code
2. Mutual transmission of channels
A channel provides two methods for transferring data between channels:
TransferTo (0, in.size(), out); /** * transfer data from a channel to target, where position, count, are * in.transferto (0, in.size(), out); */ transferTo(long position, long count, WritableByteChannel target)Copy the code
TransferFrom (in,0,in.size()); */ transferFrom(ReadableByteChannel src, long position, long count)Copy the code
The following is an example:
public class TestCopyFileByNIO { public static void fileChannelCopy(String sfPath, String tfPath) { FileInputStream fi = null; FileOutputStream fo = null; FileChannel in = null; FileChannel out = null; try { fi = new FileInputStream(new File(sfPath)); fo = new FileOutputStream(new File(tfPath)); in = fi.getChannel(); // Get the corresponding file channel out = fo.getChannel(); In.transferto (0, in.size(), out); } catch (Exception e) {e.printStackTrace();} catch (Exception e) {e.printstackTrace (); } finally { try { fi.close(); fo.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { long start = System.currentTimeMillis(); String sPath = "E:\\workspace\\comprehend-service.rar"; String tPath = "E:\\workspace\\comprehend-service-" + System.currentTimeMillis() + "-bak.rar"; fileChannelCopy(sPath, tPath); long end = System.currentTimeMillis(); System.out.println(" time: "+ (end-start) + "ms"); }}Copy the code
Results:
Time: 194msCopy the code
2.1 Maximum transmission value of a channel
The transmission size of a channel is limited. The maximum size of a channel is 2 GIGABytes, which will cause data loss. So you need to use loops to transfer data multiple times.
public class TestCopyFileByNIO {
public static void fileChannelCopy(String sfPath, String tfPath) {
FileInputStream fi = null;
FileOutputStream fo = null;
FileChannel in;
FileChannel out;
try {
fi = new FileInputStream(new File(sfPath));
fo = new FileOutputStream(new File(tfPath));
in = fi.getChannel();
out = fo.getChannel();
// Total file size
long size = in.size();
// left the number of remaining files
for (long left = size; left > 0;) { System.out.println("position = " + (size - left) + ",left = " + left);
// transferTo Returns the number transferred. The remaining minus the transferred is the current number remainingleft -= in.transferTo((size -left), left, out); }}catch (Exception e) {
e.printStackTrace();
} finally {
try {
fi.close();
fo.close();
} catch(Exception e) { e.printStackTrace(); }}}public static void main(String[] args) {
long start = System.currentTimeMillis();
String sPath = "E:\\workspace\\workspace.zip";
String tPath = "E:\\workspace\\workspace-" + System.currentTimeMillis() + "-bak.zip";
fileChannelCopy(sPath, tPath);
long end = System.currentTimeMillis();
System.out.println("用时为:" + (end - start) + "ms");
}
Copy the code
Results:
Position = 0, left = 2925330022 position = 2147483647, left = 777846375Copy the code
Path and Paths
Jdk7 introduces the Path and Paths classes
- Path indicates the file Path
- Paths is the utility class for getting Path instances
// The relative path uses the user.dir environment variable to locate 1.txt
Path source = Paths.get("1.txt");
// The absolute path represents d:\1.txt
Path source = Paths.get("d:\\1.txt");
// The absolute path also represents d:\1.txt
Path source = Paths.get("d:/1.txt");
// represents d:\data\projects
Path projects = Paths.get("d:\\data"."projects");
Copy the code
.
Represents the current path.
Represents the upper-level path
For example, the directory structure is as follows
d:
|- data
|- projects
|- a
|- b
Copy the code
code
Path path = Paths.get("d:\\data\\projects\\a\\.. \\b");
System.out.println(path);
// Normalize the path
System.out.println(path.normalize());
Copy the code
Will be output
d:\data\projects\a\.. \b d:\data\projects\bCopy the code
Four, Files
Check whether the file exists
Path path = Paths.get("helloword/data.txt");
System.out.println(Files.exists(path));
Copy the code
Creating a Level-1 Directory
Path path = Paths.get("helloword/d1");
Files.createDirectory(path);
Copy the code
- If the directory already exists, will throw exception FileAlreadyExistsException
- Do not create a multi-level directory at one time. Otherwise, NoSuchFileException will be thrown
Create a multilevel directory
Path path = Paths.get("helloword/d1/d2");
Files.createDirectories(path);
Copy the code
Copy files
Path source = Paths.get("helloword/data.txt");
Path target = Paths.get("helloword/target.txt");
Files.copy(source, target);
Copy the code
- If the file already exists, will throw exceptions FileAlreadyExistsException
If you want to override target with source, you need to use StandardCopyOption to control this
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
Copy the code
Move files
Path source = Paths.get("helloword/data.txt");
Path target = Paths.get("helloword/data.txt");
Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
Copy the code
- Move the atomicity of StandardCopyOption. ATOMIC_MOVE guarantee file
Delete the file
Path target = Paths.get("helloword/target.txt");
Files.delete(target);
Copy the code
- If the file does not exist, NoSuchFileException is thrown
Delete the directory
Path target = Paths.get("helloword/d1");
Files.delete(target);
Copy the code
- If the directory and content, will throw exception DirectoryNotEmptyException
Traverse directory files
public static void main(String[] args) throws IOException {
Path path = Paths.get("C: \ \ Program Files \ \ Java \ \ jdk1.8.0 _91");
AtomicInteger dirCount = new AtomicInteger();
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
System.out.println(dir);
dirCount.incrementAndGet();
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
System.out.println(file);
fileCount.incrementAndGet();
return super.visitFile(file, attrs); }}); System.out.println(dirCount);/ / 133
System.out.println(fileCount); / / 1479
}
Copy the code
Count the number of jars
Path path = Paths.get("C: \ \ Program Files \ \ Java \ \ jdk1.8.0 _91");
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
if (file.toFile().getName().endsWith(".jar")) {
fileCount.incrementAndGet();
}
return super.visitFile(file, attrs); }}); System.out.println(fileCount);/ / 724
Copy the code
Deleting a Multi-level Directory
Path path = Paths.get("d:\\a");
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
Files.delete(dir);
return super.postVisitDirectory(dir, exc); }});Copy the code
Delete is a dangerous operation, so make sure the folder you want to recursively delete has no important content
Copying multi-level directories
long start = System.currentTimeMillis();
String source = "D: \ \ Snipaste 1.16.2 - x64";
String target = "D: \ \ Snipaste 1.16.2 - x64aaa";
Files.walk(Paths.get(source)).forEach(path -> {
try {
String targetName = path.toString().replace(source, target);
/ / is a directory
if (Files.isDirectory(path)) {
Files.createDirectory(Paths.get(targetName));
}
// It is a normal file
else if(Files.isRegularFile(path)) { Files.copy(path, Paths.get(targetName)); }}catch(IOException e) { e.printStackTrace(); }});long end = System.currentTimeMillis();
System.out.println(end - start);
Copy the code
NIO file programming here is written here, if there is help friends a thumbs up