Summary of Basic Java Learning: Channel of NIO

Channel (Pipeline)

1. Introduction

Basically, all IOs start with a Channel in NIO. Channel is kind of like a stream. Data can be read from Channel to Buffer or written from Buffer to Channel. Here is an illustration:

Some major Channel implementations in JAVA NIO:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

2,FileChannel

FileChannel in Java NIO is a channel connecting to files. You can read and write files through file channels. FileChannel cannot be set to non-blocking mode, it always runs in blocking mode.

(1) Create FileChannel:

Before you can use FileChannel, you must create it. There are two ways to create it:

  1. The first is to use an InputStream, OutputStream, or Random Access File to get an instance of FileChannel.
  2. The second is the FileChannel.open() method, which can only be used after JDK 1.7.

(2) Write data to Channel:

FileChannel.write() method is used to write data to FileChannel. The parameter of this method is a Buffer.

while (buf.hasRemaining()){
    channel.write(buf);
}

Note that FileChannel.write() is called in the while loop. Because there is no guarantee that the write() method can write all the bytes to FileChannel at one time, it is necessary to call the write() method repeatedly until no bytes have been written to the channel in Buffer.

(3) Close Channel:

FileChannel must be closed after it is used up. Such as:

channel.close();

(4) Case 1:

Use channel to write data to a file:

package basis.StuNIO;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class StuChannel {
    public static void main(String[] args) throws Exception{
        //Get FileChannel instances using normal streams with writable permissions
        RandomAccessFile raf = new RandomAccessFile("info.txt","rw");
        FileChannel channel = raf.getChannel();

        String data = "suxing Hello\r\nsuxing Hello\nsuxing Hello\nsuxing Hello\nsuxing Hello\nsuxing Hello\nsuxing Hello\nsuxing Hello\n";
        //Create Buffer, allocate space, size to fit data
        ByteBuffer buf = ByteBuffer.allocate(1024);//Indirect memory
        buf.put(data.getBytes());
        //Switch to read mode, sure
        buf.flip();
        //Loop write data
        while (buf.hasRemaining()){
            channel.write(buf);
        }

        //Close
        channel.close();
        raf.close();


    }
}

There are several points to note in the above code:

  1. Using Random Access File to read and write data, file permissions must be RW.
  2. The size of the Buffer created should hold the data to be written.
  3. After the data is put into the Buffer, flip is necessary, otherwise empty data can only be written to the file.
  4. channel.write(buf) is put into the loop.

(5) Case 2:

Open a channel using the static method open() of the FileChannel class, and read the contents of a file using the read() method of the FileChannel.

package basis.StuNIO;

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class ChannelRead {
    public static void main(String[] args) throws Exception{
        //Open the channel using the open() method
        FileChannel channel = FileChannel.open(Paths.get("info.txt"), StandardOpenOption.READ);
        ByteBuffer buf = ByteBuffer.allocate(1024);//Indirect memory

        while (channel.read(buf)>0){//Read out the data in the hard disk and write it to the buffer.
            buf.flip();
            String data = new String(buf.array(),0,buf.limit());
            System.out.println(data);
        }

        channel.close();
    }
}

(6) FileChannel.open() source code

public static FileChannel open(Path path,
                                   Set<? extends OpenOption> options,
                                   FileAttribute<?>... attrs)
        throws IOException
    {
        FileSystemProvider provider = path.getFileSystem().provider();
        return provider.newFileChannel(path, options, attrs);
    }

    /**
     * @since   1.7
     */
    public static FileChannel open(Path path, OpenOption... options)
        throws IOException
    {
        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
        Collections.addAll(set, options);
        return open(path, set, NO_ATTRIBUTES);
    }

Both methods accept a parameter of Path interface type as the path of the file to be read.

3. Path interface, Paths tool class and Standard OpenOption

 (1)Path:

Path can be used to locate the object of the file in the file system. It usually represents a system-dependent file path. Path objects are a sequence of directory names followed by file names.

package java.nio.file;

public interface Path
    extends Comparable<Path>, Iterable<Path>, Watchable
{}

Path objects are acquired in three ways:

//First
FileSystems.getDefault().getPath();
//Second
new File("d:/a.txt").toPath();
//Third
Paths.get("d:", "a.txt");//Find a.txt file on disk d
Paths.get("a.txt"); //Find a.txt file in the project root directory

(2)Paths:

Paths, for example, return a Path by a dedicated static method by converting path strings or URI s.

There are only two static methods get() in Paths, which are used to obtain Path objects from given parameters.

package java.nio.file;

/**
 * @since 1.7
 */

public final class Paths {
    private Paths() { }

    public static Path get(String first, String... more) {
        return FileSystems.getDefault().getPath(first, more);
    }

    public static Path get(URI uri) {
        
    }
}

The get() method of the first Path accepts an indefinite parameter of String type, which is provided by the static constants of the Standard OpenOption class, representing permissions or modes for file operations (read-only, write-create, etc.).

StandardOpenOption:

StrandarOpenOption is an enumeration that provides Path's standard way of opening files.

package java.nio.file;

/**
 * Defines the standard open options.
 * @since 1.7
 */

public enum StandardOpenOption implements OpenOption {
    READ,//Reading mode
    WRITE,//Writing mode
    APPEND,//Append
    TRUNCATE_EXISTING,
    CREATE,//Establish
    CREATE_NEW,//Create a new
    DELETE_ON_CLOSE,
    SPARSE,
    SYNC,
    DSYNC;
}

 

4. Using FileChannel to Copy Picture Files

The use of direct buffer can improve the speed of reading and writing. However, the direct buffer creation and destruction costs are relatively large, and generally large file operations can significantly improve the read and write performance.

Code:

package basis.StuNIO;

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class FileChannelCopy {
    public static void main(String[] args) throws Exception{
        //Create read-write channels
        FileChannel inChannel = FileChannel.open(Paths.get("e:\\111.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("e:\\test\\haha.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        //Create a direct buffer
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        int len = 0;
        //copy
        while ((len = inChannel.read(buffer))>0){
            buffer.flip();
            outChannel.write(buffer);
            buffer.clear();
        }

        inChannel.close();
        outChannel.close();
        System.out.println("The file has been copied.");
    }
}

5. Using Memory Mapping Files to Copy Large Files

(1) MappedByteBuffer copies large files

Memory mapped files also belong to the direct buffer.

Code:

package basis.StuNIO;

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

public class StuMappedChannel {
    public static void main(String[] args) throws Exception{
        //Create channels
        FileChannel inChannel = new RandomAccessFile("e:\\111.jpg","r").getChannel();
        FileChannel outChannel = new RandomAccessFile("e:\\test\\test.jpg","rw").getChannel();
        //Use memory-mapped buffers (direct buffers)
        MappedByteBuffer map = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
        outChannel.write(map);
        //Close
        inChannel.close();
        outChannel.close();
        System.out.println("The file has been copied.");
    }
}

Note: If the file exceeds 2G, it needs to be mapped into multiple files.

(2)MappedByteBuffer:

Buffered Reader, Buffered InputStream and other buffer IO classes are usually used in java io operations to process large files. However, in java nio, a method based on MappedByteBuffer is introduced to operate large files. Its reading and writing performance is very high. The FileChannel.map() method can obtain an instance of the abstract class.

Inheritance relationships and class declarations:

java.lang.Object 
|___java.nio.Buffer 
    |___java.nio.ByteBuffer 
        |___java.nio.MappedByteBuffer 

package java.nio;

/**
 * @since 1.4
 */

public abstract class MappedByteBuffer extends ByteBuffer{}

In terms of inheritance structure, MappedByteBuffer inherits from ByteBuffer and maintains a logical address address internally. FileChannel provides a map method to map files to virtual memory. Usually, the whole file can be mapped. If the file is large, it can be segmented.

The internal class MapMode in FileChannel provides access to memory image files for MappedByteBuffer:

MapMode mode:

  1. MapMode.READ_ONLY: Read-only, attempting to modify the resulting buffer will cause an exception to be thrown.
  2. MapMode.READ_WRITE: Read/write, and changes to the resulting buffer will eventually be written to the file; however, this change is not necessarily visible to other programs mapped to the same file.
  3. MapMode.PRIVATE: Private, readable and writable, but the modified content will not be written to the file, but the buffer itself changes, which is called "copy on write".

 

Keywords: Programming Java iOS JDK

Added by tnkannan on Wed, 14 Aug 2019 15:29:59 +0300