This is the 11th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021
FileChannel
A FileChannel is a channel that operates on a file. Note that a FileChannel only works in blocking mode and therefore cannot be matched with a Selector.
Create FileChannel
There is no constructor for FileChannel, but a FileChannel is retrieved by FileInputStream, FileOutputStream, or RandomAccessFile, which all have a getChannel method, But their use is different:
- FileChannel obtained by FileInputStream can only be read
- FileChannel obtained via FileOutputStream can only be written
- Whether a FileChannel retrieved from RandomAccessFile can read and write depends on the read and write mode at the time RandomAccessFile was constructed
FileChannel f1 = new FileInputStream("data.txt").getChannel();
FileChannel f2 = new FileOutputStream("data.txt").getChannel();
FileChannel f3 = new RandomAccessFile("data.txt"."rw").getChannel();
Copy the code
Read the content
The channel of the file can be obtained via FileInputStream, and the data is written to ByteBuffer using the read method. The return value of the read method is the number of bytes read, and -1 is returned if the end of the file is read. You can tell if the read is complete by the return value of the read method.
public static void main(String[] args) throws IOException {
FileChannel f1 = new FileInputStream("data.txt").getChannel();
ByteBuffer buffer = ByteBuffer.allocate(10000);
int value = 0;
while((value = f1.read(buffer))>0)
{
System.out.println("\n============="+value);
buffer.flip();
while(buffer.hasRemaining())
System.out.print(((char) buffer.get()));
buffer.flip();
}
f1.close();
}
Copy the code
Write content
You can get the file’s channel via FileOutputStream and write the buffer to the specified file using the write method. Note that since channels also have sizes, Therefore, the write method does not guarantee that all the contents of the buffer will be written to a channel at once. Write must follow the following rules:
While (buffer.hasRemaining()) {channel.write(buffer); // Use the hasRemaining() method to check whether there is any data in the buffer that is not written to the channel. }Copy the code
Second, always use buffer’s flip method to convert the mode of buffer, otherwise it will write garbled characters.
public static void main(String[] args) throws IOException {
FileChannel f1 = new FileOutputStream("data2.txt").getChannel();
ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.put("hello wolrd!".getBytes(StandardCharsets.UTF_8));
buffer.flip();
while(buffer.hasRemaining())
{
f1.write(buffer);
}
f1.close();
}
Copy the code
Shut down
Channels need to be closed, and are usually closed by try-with-resource. It is best to obtain the stream and channel using the following method to avoid any reason for the resource not to be closed
public static void main(String[] args) throws IOException { try (FileInputStream fis = new FileInputStream("stu.txt"); FileOutputStream fos = new FileOutputStream("student.txt"); FileChannel inputChannel = fis.getChannel(); FileChannel outputChannel = fos.getChannel()) {// Perform the corresponding operation}}Copy the code
The location of the FileChannel
Buffer has a variable position that indicates the index of the next read/write position. You have a property position in the FileChannel that holds the position where the data is read
long pos = channel.position();
Copy the code
Position (int pos) can be used to set the value of position in a channel, if the current position is set to the end of the file
- The read will return -1
- If position goes beyond the end of the file, there will be a void (00) between the new content and the end of the file.
Compulsory to write
For performance reasons, the operating system caches data, not immediately writing it to disk, but writing all data to disk once the cache is full. You can call the force(true) method to write file contents and metadata (information such as file permissions) to disk immediately.
Two FileChannel transfer data
TransferTo method
The transferTo method can be used to transfer data from one channel to another channel quickly and efficiently, but only 2G content can be transferred at a time. TransferTo takes three parameters: position, transfer size, and destination channel
public static void main(String[] args) throws IOException {
try(
FileChannel f1 = new FileInputStream("data.txt").getChannel();
FileChannel f2 = new FileOutputStream("data2.txt").getChannel();) { System.out.println("Size before transmission: F1 size:"+f1.size()+" f2大小: "+f2.size());
f1.transferTo(0,f1.size(),f2);
System.out.println("Size after transmission: F1 size:"+f1.size()+" f2大小: "+f2.size());
}catch (IOException e) { }
}
Copy the code
Results show:
Transmission over 2G
The transferTo method can only transfer content of less than 2G at a time, but the content of more than 2G can be repeatedly transferred in a loop until the transfer is complete:
try(
FileChannel f1 = new FileInputStream("data.txt").getChannel();
FileChannel f2 = new FileOutputStream("data2.txt").getChannel();) {long size = f1.size();
long capacity = f1.size();
while(capacity>0)
{
longthisTransfor = f1.transferTo(size - capacity , capacity, f2); capacity -= thisTransfor; }}catch (IOException e) { }
Copy the code
The Path and the Paths
- Path indicates the file Path
- Paths is the utility class for getting Path instances
Path source = Paths.get("1.txt"); // The relative path does not contain a drive letter. Use the user.dir environment variable to locate 1.txt
Path source = Paths.get("d:\\1.txt"); // The absolute path represents the d:\1.txt backslash that needs to be escaped
Path source = Paths.get("d:/1.txt"); // The absolute path also represents d:\1.txt
Path projects = Paths.get("d:\\data"."projects"); // splice represents d:\data\projects
Copy the code
Files
To find the
You can use the Files utility class to check for the existence of Files
Path path = Paths.get("data.txt");
System.out.println(Files.exists(path));
Copy the code
create
If you want to create a level 1 directory:
Path path = Paths.get("study/java");
Files.createDirectory(path);
Copy the code
Two points need to be noted
- If the directory already exists, will throw exception FileAlreadyExistsException
- Do not create a multi-level directory at one time. Otherwise, NoSuchFileException will be thrown
To create a multilevel directory:
Path path = Paths.get("study/java/nio");
Files.createDirectories(path);
Copy the code
Copy mobile
Copy Files can use the copy function in the class Files tool, it is important to note that if the file already exists, will throw exceptions FileAlreadyExistsException
Path source = Paths.get("java/data.txt");
Path target = Paths.get("java/data1.txt");
Files.copy(source, target);
Copy the code
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 can use Files tool move function in the class, if the third parameter StandardCopyOption. ATOMIC_MOVE guarantee Files mobile atomicity
Path source = Paths.get("java/data.txt");
Path target = Paths.get("study/data.txt");
Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
Copy the code
delete
To delete a file, use the delete method in the Files utility class. Note that NoSuchFileException will be thrown if the file does not exist.
Path target = Paths.get("study/data.txt");
Files.delete(target);
Copy the code
Delete the directory and delete Files, all is to use the delete method in the class Files tool, but it is important to note that if the directory and content, will throw exceptions DirectoryNotEmptyException, so can only delete empty directory, if you want to delete is not empty, You can go through all the files in the directory and delete those files and subdirectories, and then delete the directory. However, the Files utility class also provides a more convenient method, the walkFileTree method, described in the next section.
Path target = Paths.get("study/java");
Files.delete(target);
Copy the code
The walkFileTree method
The walkFileTree(Path, FileVisitor) method in the Files utility class makes it easier to manipulate subdirectories and Files in a directory by passing in two parameters
-
Path: indicates the start Path of the file
-
FileVisitor: a file accessor that uses the visitor pattern. There are four methods that can pass in a new SimpleFileVisitor and override the class:
- PreVisitDirectory: Operations performed before accessing a directory
- VisitFile: Operations for accessing files
- VisitFileFailed: Operations performed when a file fails to be accessed
- PostVisitDirectory: Operations performed after a directory is accessed
Statistics by walkFileTree
Use walkFileTree to count the number of all directories and files in a directory:
public static void main(String[] args) throws IOException {
Path path = Paths.get("E:\\ppt\\");
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
dicAccount.incrementAndGet();
System.out.println("= = = >"+dir);
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
fileAccount.incrementAndGet();
File f = new File(file.toString());
Files.delete(file);
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return super.visitFileFailed(file, exc);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println(dir+"< = = =");
Files.delete(dir);
return super.postVisitDirectory(dir, exc); }}); System.out.println("dicAccount " + dicAccount.get());
System.out.println("fileAccount "+ fileAccount.get());
}
Copy the code
Results show:
The walkFileTree method can also delete all Files and subdirectories in a directory, but it is important to note that the files. delete method can only delete empty directories, so you need to delete Files in visiteFile first. Then delete the subdirectory in the postVisitDirecory method.
Copying multi-level directories
Files.walk(Paths.get(source)).forEach(path1 -> {
try{
String name = path1.toString().replace(source,target);
if(Files.isDirectory(path1))
{
Files.createDirectories(Paths.get(name));
}
else if(Files.isRegularFile(path1)) { Files.copy(path1,Paths.get(target)); }}catch(IOException e) { e.printStackTrace(); }});Copy the code