`
Donald_Draper
  • 浏览: 984406 次
社区版块
存档分类
最新评论

FileChanne定义

    博客分类:
  • NIO
nio 
阅读更多
文件读写方式简单综述:http://donald-draper.iteye.com/blog/2374237
FileChannel示例:http://donald-draper.iteye.com/blog/2373661
SeekableByteChannel接口定义:http://donald-draper.iteye.com/blog/2373700
前面看了一下SeekableByteChannel接口定义,今天来看一下FileChannel的定义
package java.nio.channels;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.nio.file.*;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.spi.*;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;

/**
 * A channel for reading, writing, mapping, and manipulating a file.
 *FileChannel是一个可读,可写,可映射和操纵文件的通道。
 *  A file channel is a {@link SeekableByteChannel} that is connected to
 * a file. It has a current <i>position</i> within its file which can
 * be both {@link #position() <i>queried</i>} and {@link #position(long)
 * <i>modified</i>}.  The file itself contains a variable-length sequence
 * of bytes that can be read and written and whose current {@link #size
 * <i>size</i>} can be queried.  The size of the file increases
 * when bytes are written beyond its current size; the size of the file
 * decreases when it is {@link #truncate </code><i>truncated</i><code>}.  The
 * file may also have some associated <i>metadata</i> such as access
 * permissions, content type, and last-modification time; this class does not
 * define methods for metadata access.
 *FileChannel是一个SeekableByteChannel,可以连接文件。文件当前的位置可以通过
 postion方法查询,通过#position(long)修改。文件的包含的字节序列长度可以通过size方法
 获取。如果字节被写到文件,则文件大小将会增加。当调用#truncate方法,压缩文件时,
 文件大小将会减少。文件还有一些元数据,比如权限,内容类型,上次修改时间,FileChannle没有
 提供访问元数据的方法。
 *  In addition to the familiar read, write, and close operations of byte
 * channels, this class defines the following file-specific operations: 

 *另外还有熟悉的字节通道的read,write, and close方法,FileChannle定位文件具体的操作如下:
 * [list]
 *
 *   <li> Bytes may be {@link #read(ByteBuffer, long) read} or
 *   {@link #write(ByteBuffer, long) <i>written</i>} at an absolute
 *   position in a file in a way that does not affect the channel's current
 *   position.  
</li>
 *   写buffer和读字节序列到buffer是以文件的绝对位置,不会影响通道的当前位置。
 *   <li> A region of a file may be {@link #map <i>mapped</i>}
 *   directly into memory; for large files this is often much more efficient
 *   than invoking the usual <tt>read</tt> or <tt>write</tt> methods.
 文件的region可以直接映射到内存中,这对于大文件的读写效率较高。
 *   
</li>
 *
 *   <li> Updates made to a file may be {@link #force <i>forced
 *   out</i>} to the underlying storage device, ensuring that data are not
 *   lost in the event of a system crash.  
</li>
 通过force方法可以将对文件的更新,强制写到底层存储设备,确保数据不会因系统崩溃而丢失。
 *
 *   <li> Bytes can be transferred from a file {@link #transferTo <i>to
 *   some other channel</i>}, and {@link #transferFrom <i>vice
 *   versa</i>}, in a way that can be optimized by many operating systems
 *   into a very fast transfer directly to or from the filesystem cache.
 字节序列可以用#transferTo方法从一个文件传输到其他通道,#transferFrom方法相反,
 这样可以优化许多系统操作,可快速直接地利用文件缓存。
 *   
</li>
 *
 *   <li> A region of a file may be {@link FileLock <i>locked</i>}
 *   against access by other programs.  
</li>
 文件的region可以通过FileLock锁住,防止其他程序访问。
 *
 * [/list]
 *
 *  File channels are safe for use by multiple concurrent threads.  The
 * {@link Channel#close close} method may be invoked at any time, as specified
 * by the {@link Channel} interface.  Only one operation that involves the
 * channel's position or can change its file's size may be in progress at any
 * given time; attempts to initiate a second such operation while the first is
 * still in progress will block until the first operation completes.  Other
 * operations, in particular those that take an explicit position, may proceed
 * concurrently; whether they in fact do so is dependent upon the underlying
 * implementation and is therefore unspecified.
 *文件通道多线程并发访问时,是安全的。close方法可以在任何时候调用,与Channel接口相似。
 涉及到通道position位置的操作或改变文件大小的操作,也许可以在任何进行;在进行这些操作时,
 如果有其他操作正在执行,必须等待先前操作完成。

 * <p> The view of a file provided by an instance of this class is guaranteed
 * to be consistent with other views of the same file provided by other
 * instances in the same program.  The view provided by an instance of this
 * class may or may not, however, be consistent with the views seen by other
 * concurrently-running programs due to caching performed by the underlying
 * operating system and delays induced by network-filesystem protocols.  This
 * is true regardless of the language in which these other programs are
 * written, and whether they are running on the same machine or on some other
 * machine.  The exact nature of any such inconsistencies are system-dependent
 * and are therefore unspecified.
 *文件视图的提供者必须保证与相同应用程序的提供者与相同文件的视图一致。由于底层操作系统
 缓存执行和网络文件协议导致的延时,文件通道实例的视图可能会,也可能不会与其他并发执行
 的程序看的视图一致。无论他们运行相同的机器上,还是其他机器上,忽略这些程序写的语言,
 视图是一致的。由于其他依赖系统的天然不一致性,因此是不确定的。这段话讲的意思,为
 不同文件通道的实例(关联相同的文件)的文件系统提供者(Path提供者)必须保持文件的视图的一致性,
 由于底层操作系统的缓存执行和网络文件系统协议引起延时,以及依赖系统底层的相关天然属性不同,
 可能导致文件视图的不一致性。
 * <p> A file channel is created by invoking one of the {@link #open open}
 * methods defined by this class. A file channel can also be obtained from an
 * existing {@link java.io.FileInputStream#getChannel FileInputStream}, {@link
 * java.io.FileOutputStream#getChannel FileOutputStream}, or {@link
 * java.io.RandomAccessFile#getChannel RandomAccessFile} object by invoking
 * that object's <tt>getChannel</tt> method, which returns a file channel that
 * is connected to the same underlying file. Where the file channel is obtained
 * from an existing stream or random access file then the state of the file
 * channel is intimately connected to that of the object whose <tt>getChannel</tt>
 * method returned the channel.  Changing the channel's position, whether
 * explicitly or by reading or writing bytes, will change the file position of
 * the originating object, and vice versa. Changing the file's length via the
 * file channel will change the length seen via the originating object, and vice
 * versa.  Changing the file's content by writing bytes will change the content
 * seen by the originating object, and vice versa.
 *通过open方法可以创建一个文件通道。文件通道也可以通过FileInputStream#getChannel,
FileOutputStream#getChannel,RandomAccessFile#getChannel方法获取文件通道,调用
他们的#getChannel,将返回连接底层文件的文件通道。从已经存在的流或随机访问文件获取的
文件通道,文件通道状态默认是连接流或随机文件的对应文件。无论是读或写字节序列,将会改变
通道的position位置,同时会改变流或随机文件的对应文件位置,反之亦然。通道改变文件的长度,
同时会改变流或随机文件的对应文件长度,反之亦然。写字节序列改变文件的内容,同时会改变流或
随机文件的对应文件内容,反之亦然。这几句话的含义为,及文件通道和流或随机文件保持一致性。
 * <a name="open-mode"></a> <p> At various points this class specifies that an
 * instance that is "open for reading," "open for writing," or "open for
 * reading and writing" is required.  A channel obtained via the {@link
 * java.io.FileInputStream#getChannel getChannel} method of a {@link
 * java.io.FileInputStream} instance will be open for reading.  A channel
 * obtained via the {@link java.io.FileOutputStream#getChannel getChannel}
 * method of a {@link java.io.FileOutputStream} instance will be open for
 * writing.  Finally, a channel obtained via the {@link
 * java.io.RandomAccessFile#getChannel getChannel} method of a {@link
 * java.io.RandomAccessFile} instance will be open for reading if the instance
 * was created with mode <tt>"r"</tt> and will be open for reading and writing
 * if the instance was created with mode <tt>"rw"</tt>.
 *根据不同的需要,我们需要以读模式,写模式或读写模式打开一个实例。通过FileInputStream#getChannel
 将会以读模式打开,.FileOutputStream#getChannel将以写模式打开。RandomAccessFile#getChannel
 方法如果以r模式创建RandomAccessFile则是只读模式,rw则为读写模式。
 * <a name="append-mode"></a><p> A file channel that is open for writing may be in
 * <i>append mode</i>, for example if it was obtained from a file-output stream
 * that was created by invoking the {@link
 * java.io.FileOutputStream#FileOutputStream(java.io.File,boolean)
 * FileOutputStream(File,boolean)} constructor and passing <tt>true</tt> for
 * the second parameter.  In this mode each invocation of a relative write
 * operation first advances the position to the end of the file and then writes
 * the requested data.  Whether the advancement of the position and the writing
 * of the data are done in a single atomic operation is system-dependent and
 * therefore unspecified.
 *可能在append模式下,以写模式打开的文件通道,比如通过FileOutputStream#FileOutputStream(java.io.File,boolean)
 方法,boolean参数为true。在此模式下,每次写字节序列,先将position定位到文件的末尾,才开始
 写请求数据。postion是否移动文件末尾,字节序列是否已经写到存储设备,这要依赖于具体的系统,
 因此是不确定的。
 * @see java.io.FileInputStream#getChannel()//读模式
 * @see java.io.FileOutputStream#getChannel()//写模式
 * @see java.io.RandomAccessFile#getChannel()//以创建RandomAccessFile的模式为准,r,rw。
 *
 * @author Mark Reinhold
 * @author Mike McCloskey
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class FileChannel
    extends AbstractInterruptibleChannel
    implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
{
    /**
     * Initializes a new instance of this class.
     */
    protected FileChannel() { }

    /**
     * Opens or creates a file, returning a file channel to access the file.
     *打开或创建一个文件,返回一个访问文件的通道。
     * <p> The {@code options} parameter determines how the file is opened.
     * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE
     * WRITE} options determine if the file should be opened for reading and/or
     * writing. If neither option (or the {@link StandardOpenOption#APPEND APPEND}
     * option) is contained in the array then the file is opened for reading.
     * By default reading or writing commences at the beginning of the file.
     *options决定了如何打开一个文件。StandardOpenOption#READ/WRITE选项配置决定是否
     为读/写操作打开。如果配置选项中有其他选项(StandardOpenOption#APPEND),则,文件
     只能进行从文件的尾部进行读写操作。
     * <p> In the addition to {@code READ} and {@code WRITE}, the following
     * options may be present:
     *除了读写选项,还有其他一些选项,如下
     * <table border=1 cellpadding=5 summary="">
     * <tr> <th>Option</th> <th>Description</th> </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
     *   <td> If this option is present then the file is opened for writing and
     *     each invocation of the channel's {@code write} method first advances
     *     the position to the end of the file and then writes the requested
     *     data. Whether the advancement of the position and the writing of the
     *     data are done in a single atomic operation is system-dependent and
     *     therefore unspecified. This option may not be used in conjunction
     *     with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td>
     如果选项集中StandardOpenOption#APPEND,且文件打开进行写操作,每次调用通道的
     write方法,首先将position定位前进到文件的末尾,才进行写数据。由于position的移动
     和写数据操作,在一个依赖于系统的原子操作中,因此是不确定的。此配置不能和READ与TRUNCATE_EXISTING
     选项一起使用
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
     *   <td> If this option is present then the existing file is truncated to
     *   a size of 0 bytes. This option is ignored when the file is opened only
     *   for reading. </td>
     StandardOpenOption#TRUNCATE_EXISTING将已经存在的file压缩到0字节。当以读模式打开
     文件时,此选项默认忽略。
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
     *   <td> If this option is present then a new file is created, failing if
     *   the file already exists. When creating a file the check for the
     *   existence of the file and the creation of the file if it does not exist
     *   is atomic with respect to other file system operations. This option is
     *   ignored when the file is opened only for reading. </td>
     #CREATE_NEW选项创建一个新的文件,如果文件已经存在,则失败。在创建文件时,检查
     文件是否存在,如果不存在,则创建文件,相对于其他文件系统操作,创建文件是原子化的操作。
     当文件以只读模式打开时,此选项配置忽略。
     * </tr>
     * <tr>
     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
     *   <td> If this option is present then an existing file is opened if it
     *   exists, otherwise a new file is created. When creating a file the check
     *   for the existence of the file and the creation of the file if it does
     *   not exist is atomic with respect to other file system operations. This
     *   option is ignored if the {@code CREATE_NEW} option is also present or
     *   the file is opened only for reading. </td>
     #CREATE选项,如果文件存在,则打开文件,否则创建一个新的文件。在创建文件时,
     检查文件是否存在,如果不存在,则创建文件,相对于其他文件系统操作,创建文件是原子化的操作。
     当文件以只读模式打开时或选项集中有CREATE_NEW时,此选项配置忽略。
     * </tr>
     * <tr>
     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
     *   <td> When this option is present then the implementation makes a
     *   [i]best effort[/i] attempt to delete the file when closed by the
     *   the {@link #close close} method. If the {@code close} method is not
     *   invoked then a [i]best effort[/i] attempt is made to delete the file
     *   when the Java virtual machine terminates. </td>
     DELETE_ON_CLOSE选项,当文件调用close方法,关闭文件时,尽最大努力删除文件。
     当虚拟机终止时,不能调用close方法,尽最大努力删除文件。
     * </tr>
     * <tr>
     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
     *   <td> When creating a new file this option is a [i]hint[/i] that the
     *   new file will be sparse. This option is ignored when not creating
     *   a new file. </td>
     SPARSE选项,当创建一个文件时,表示创建的文件是稀疏的,了解稀疏矩阵的话,应该知道
     这个意思,大概就是压缩存储文件。当不能创建一个新的文件时,此选项忽略。
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
     *   <td> Requires that every update to the file's content or metadata be
     *   written synchronously to the underlying storage device. (see <a
     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
     *   integrity</a>). </td>
     SYNC选项,在每次更新文件内容或元数据时,同步的底层存储设备。
     * <tr>
     * <tr>
     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
     *   <td> Requires that every update to the file's content be written
     *   synchronously to the underlying storage device. (see <a
     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
     *   integrity</a>). </td>
     DSYNC选项,在每次更新文件内容时,同步的底层存储设备。
     * </tr>
     * </table>
     *
     * <p> An implementation may also support additional options.
     *一个具体的实现也许支持其他选项
     * <p> The {@code attrs} parameter is an optional array of file {@link
     * FileAttribute file-attributes} to set atomically when creating the file.
     *文件属性参数数组attrs,在创建文件时自动设置。
     * <p> The new channel is created by invoking the {@link
     * FileSystemProvider#newFileChannel newFileChannel} method on the
     * provider that created the {@code Path}.
     *通道通过调用FileSystemProvider#newFileChannel创建通道,provider为创建Path的
     provider。
     * @param   path
     *          The path of the file to open or create
     * @param   options
     *          Options specifying how the file is opened
     * @param   attrs
     *          An optional list of file attributes to set atomically when
     *          creating the file
     *
     * @return  A new file channel
     *
     * @throws  IllegalArgumentException//包含无效选项
     *          If the set contains an invalid combination of options
     * @throws  UnsupportedOperationException
     *          If the {@code path} is associated with a provider that does not
     *          support creating file channels, or an unsupported open option is
     *          specified, or the array contains an attribute that cannot be set
     *          atomically when creating the file
     如果path的提供者不支持创建通道,或有不支持的open选项,或者当文件创建时,
     文件属性自动设置。
     * @throws  IOException
     *          If an I/O error occurs
     * @throws  SecurityException
     *          If a security manager is installed and it denies an
     *          unspecified permission required by the implementation.
     *          In the case of the default provider, the {@link
     *          SecurityManager#checkRead(String)} method is invoked to check
     *          read access if the file is opened for reading. The {@link
     *          SecurityManager#checkWrite(String)} method is invoked to check
     *          write access if the file is opened for writing
     如果安全管理器安装,拒绝了具体实现需要的允许。如果文件以读模式打开,则默认的提供者
     需要检查读权限,相应的写操作,要检验写权限。
     *
     * @since   1.7
     */
    public static FileChannel open(Path path,
                                   Set<? extends OpenOption> options,
                                   FileAttribute<?>... attrs)
        throws IOException
    {
        //从Path获取文件系统提供者
        FileSystemProvider provider = path.getFileSystem().provider();
        return provider.newFileChannel(path, options, attrs);
    }
    //文件属性
    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];

    /**
     * Opens or creates a file, returning a file channel to access the file.
     *根据Path和打开选项,打开或创建一个文件,返回访问文件的通道
     * <p> An invocation of this method behaves in exactly the same way as the
     * invocation
     * <pre>
     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, opts, new FileAttribute<?>[0]);
     * </pre>
     * where {@code opts} is a set of the options specified in the {@code
     * options} array.
     *
     * @param   path
     *          The path of the file to open or create
     * @param   options
     *          Options specifying how the file is opened
     *
     * @return  A new file channel
     *
     * @throws  IllegalArgumentException
     *          If the set contains an invalid combination of options
     * @throws  UnsupportedOperationException
     *          If the {@code path} is associated with a provider that does not
     *          support creating file channels, or an unsupported open option is
     *          specified
     * @throws  IOException
     *          If an I/O error occurs
     * @throws  SecurityException
     *          If a security manager is installed and it denies an
     *          unspecified permission required by the implementation.
     *          In the case of the default provider, the {@link
     *          SecurityManager#checkRead(String)} method is invoked to check
     *          read access if the file is opened for reading. The {@link
     *          SecurityManager#checkWrite(String)} method is invoked to check
     *          write access if the file is opened for writing
     *
     * @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);
	//委托给open(Path path,Set<? extends OpenOption> options,FileAttribute<?>... attrs)
        return open(path, set, NO_ATTRIBUTES);
    }

    // -- Channel operations --

    /**
     * Reads a sequence of bytes from this channel into the given buffer.
     *从通道读取字节序列,写到给定的buffer中
     * <p> Bytes are read starting at this channel's current file position, and
     * then the file position is updated with the number of bytes actually
     * read.  Otherwise this method behaves exactly as specified in the {@link
     * ReadableByteChannel} interface. 

     字节从通道的当前位置读取,当字节被读取时,position自动更新。其他和ReadableByteChannel
     相同。
     */
    public abstract int read(ByteBuffer dst) throws IOException;

    /**
     * Reads a sequence of bytes from this channel into a subsequence of the
     * given buffers.
     *从通道读取字节序列,写到给定的buffer数组中
     *  Bytes are read starting at this channel's current file position, and
     * then the file position is updated with the number of bytes actually
     * read.  Otherwise this method behaves exactly as specified in the {@link
     * ScatteringByteChannel} interface.  

     字节从通道的当前位置读取,当字节被读取时,position自动更新。其他和ScatteringByteChannel
     相同。
     */
    public abstract long read(ByteBuffer[] dsts, int offset, int length)
        throws IOException;

    /**
     * Reads a sequence of bytes from this channel into the given buffers.
     *从通道读取字节序列,写到给定的buffer数组中
     *  Bytes are read starting at this channel's current file position, and
     * then the file position is updated with the number of bytes actually
     * read.  Otherwise this method behaves exactly as specified in the {@link
     * ScatteringByteChannel} interface.  

     字节从通道的当前位置读取,当字节被读取时,position自动更新。其他和ScatteringByteChannel
     相同。
     */
    public final long read(ByteBuffer[] dsts) throws IOException {
        return read(dsts, 0, dsts.length);
    }

    /**
     * Writes a sequence of bytes to this channel from the given buffer.
     *从buffer读取字节序列,写到通道中。
     *  Bytes are written starting at this channel's current file position
     * unless the channel is in append mode, in which case the position is
     * first advanced to the end of the file.  The file is grown, if necessary,
     * to accommodate the written bytes, and then the file position is updated
     * with the number of bytes actually written.  Otherwise this method
     * behaves exactly as specified by the {@link WritableByteChannel}
     * interface. 

     从通道文件的当前位置开始写字节序列,如果是append模式,则position定位到文件的末尾。
     如果有字节写入文件,则更新position。其他和WritableByteChannel相同。
     */
    public abstract int write(ByteBuffer src) throws IOException;

    /**
     * Writes a sequence of bytes to this channel from a subsequence of the
     * given buffers.
     *从buffer数组读取字节序列,写到通道中。
     *  Bytes are written starting at this channel's current file position
     * unless the channel is in append mode, in which case the position is
     * first advanced to the end of the file.  The file is grown, if necessary,
     * to accommodate the written bytes, and then the file position is updated
     * with the number of bytes actually written.  Otherwise this method
     * behaves exactly as specified in the {@link GatheringByteChannel}
     * interface.  

     从通道文件的当前位置开始写字节序列,如果是append模式,则position定位到文件的末尾。
     如果有字节写入文件,则更新position。其他和WritableByteChannel相同
     */
    public abstract long write(ByteBuffer[] srcs, int offset, int length)
        throws IOException;

    /**
     * Writes a sequence of bytes to this channel from the given buffers.
     *从buffer数组读取字节序列,写到通道中。
     *  Bytes are written starting at this channel's current file position
     * unless the channel is in append mode, in which case the position is
     * first advanced to the end of the file.  The file is grown, if necessary,
     * to accommodate the written bytes, and then the file position is updated
     * with the number of bytes actually written.  Otherwise this method
     * behaves exactly as specified in the {@link GatheringByteChannel}
     * interface.  

     从通道文件的当前位置开始写字节序列,如果是append模式,则position定位到文件的末尾。
     如果有字节写入文件,则更新position。其他和WritableByteChannel相同
     */
    public final long write(ByteBuffer[] srcs) throws IOException {
        return write(srcs, 0, srcs.length);
    }


    // -- Other operations --

    /**
     * Returns this channel's file position.  
     *返回文件的当前位置
     * @return  This channel's file position,
     *          a non-negative integer counting the number of bytes
     *          from the beginning of the file to the current position
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long position() throws IOException;

    /**
     * Sets this channel's file position.
     *设置通道文件的当前位置
     *  Setting the position to a value that is greater than the file's
     * current size is legal but does not change the size of the file.  A later
     * attempt to read bytes at such a position will immediately return an
     * end-of-file indication.  A later attempt to write bytes at such a
     * position will cause the file to be grown to accommodate the new bytes;
     * the values of any bytes between the previous end-of-file and the
     * newly-written bytes are unspecified.  

     *如果设置的位置大于当前文件的size是允许的,但不会改变文件的大小。修改如果
     尝试读取字节序列,position将定位到文件的末尾,并返回。尝试在新位置写字节,将会引起
     文件的增长,在先前文件的末尾和新写的字节序列之间的字节序列值是不确定的。
     * @param  newPosition
     *         The new position, a non-negative integer counting
     *         the number of bytes from the beginning of the file
     *
     * @return  This file channel
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IllegalArgumentException
     *          If the new position is negative
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract FileChannel position(long newPosition) throws IOException;

    /**
     * Returns the current size of this channel's file.  </p>
     *返回通道文件的当前大小。
     * @return  The current size of this channel's file,
     *          measured in bytes
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long size() throws IOException;

    /**
     * Truncates this channel's file to the given size.
     压缩通道文件到指定的大小
     *  If the given size is less than the file's current size then the file
     * is truncated, discarding any bytes beyond the new end of the file.  If
     * the given size is greater than or equal to the file's current size then
     * the file is not modified.  In either case, if this channel's file
     * position is greater than the given size then it is set to that size.
     * 

     *如果给定的size小于当前文件的大小,则文件将被压缩,丢弃新文件末尾后的字节序列。
     如果给定size大于或等于当前文件大小,文件不会修改。在一些具体的实现中,如果position的位置
     大于给定size,将会position定位到给定的size。
     * @param  size
     *         The new size, a non-negative byte count
     *
     * @return  This file channel
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IllegalArgumentException
     *          If the new size is negative
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract FileChannel truncate(long size) throws IOException;

    /**
     * Forces any updates to this channel's file to be written to the storage
     * device that contains it.
     *强制将通道文件的所有更新写到存储设备上。
     *  If this channel's file resides on a local storage device then when
     * this method returns it is guaranteed that all changes made to the file
     * since this channel was created, or since this method was last invoked,
     * will have been written to that device.  This is useful for ensuring that
     * critical information is not lost in the event of a system crash.
     *如果通道文件存在本地存储设备上,当方法返回时,可以保证从通道创建或方法上一次调用,
     所有文件的改变,将会被写到设备上。这样在系统崩溃时,可以保证关键的信息不回丢失。
     * <p> If the file does not reside on a local device then no such guarantee
     * is made.
     *如果文件不在本地设备上,则不能保证。
     * <p> The <tt>metaData</tt> parameter can be used to limit the number of
     * I/O operations that this method is required to perform.  Passing
     * <tt>false</tt> for this parameter indicates that only updates to the
     * file's content need be written to storage; passing <tt>true</tt>
     * indicates that updates to both the file's content and metadata must be
     * written, which generally requires at least one more I/O operation.
     * Whether this parameter actually has any effect is dependent upon the
     * underlying operating system and is therefore unspecified.
     *metaData参数可以用于限制方法需要执行IO操作的数量。metaData为false,
     需要强制将文件的内容更新写到存储设备中,为true,则需要强制将文件的内容和
     元数据的更新写到存储设备中,这种情况通道需要至少一次IO操作。参数metaData
     是否有效依赖于具体的底层操作系统,因此是不确定的。
     * <p> Invoking this method may cause an I/O operation to occur even if the
     * channel was only opened for reading.  Some operating systems, for
     * example, maintain a last-access time as part of a file's metadata, and
     * this time is updated whenever the file is read.  Whether or not this is
     * actually done is system-dependent and is therefore unspecified.
     *如果通道以读模式打开,调用此方法可能会引起IO操作的发生。一些系统操作,
     比如维护做文件元数据的一部分的文件上一次访问时间,无论何时访问文件,
     此时间将会更新。具体是否更新依赖于具体的底层操作系统,因此是不确定的。
     * <p> This method is only guaranteed to force changes that were made to
     * this channel's file via the methods defined in this class.  It may or
     * may not force changes that were made by modifying the content of a
     * {@link MappedByteBuffer <i>mapped byte buffer</i>} obtained by
     * invoking the {@link #map map} method.  Invoking the {@link
     * MappedByteBuffer#force force} method of the mapped byte buffer will
     * force changes made to the buffer's content to be written.  

     *此方法仅能保证通过此类的方法强制通道文件改变更新到设备,即具体做了哪些强制
     操作依据此类的此方法的具体实现。也许调用map获取一个文件映射buffer,对内存的修改
     不会强制写到设备。调用MappedByteBuffer#force方法,将会将buffer改变强制写到设备上。
     * @param   metaData
     *          If <tt>true</tt> then this method is required to force changes
     *          to both the file's content and metadata to be written to
     *          storage; otherwise, it need only force content changes to be
     *          written
     *如果metaData为true,需要强制将文件的内容和元数据写到存储设备中,否则
     需要强制将文件的内容写到存储设备中。
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract void force(boolean metaData) throws IOException;

    /**
     * Transfers bytes from this channel's file to the given writable byte
     * channel.
     *读取本通道的字节序列,写到可写字节通道中。
     *  An attempt is made to read up to <tt>count</tt> bytes starting at
     * the given <tt>position</tt> in this channel's file and write them to the
     * target channel.  An invocation of this method may or may not transfer
     * all of the requested bytes; whether or not it does so depends upon the
     * natures and states of the channels.  Fewer than the requested number of
     * bytes are transferred if this channel's file contains fewer than
     * <tt>count</tt> bytes starting at the given <tt>position</tt>, or if the
     * target channel is non-blocking and it has fewer than <tt>count</tt>
     * bytes free in its output buffer.
     *从当前通道文件的position位置,读取count字节序列,写到目标通道中。调用此方法也许会,也许不会
     传输所有请求的字节序列;具体是否全部传输依赖于通道状态和性质。如果通道文件中,从
     position开始没有count个字节,或者目标通道是一个非阻塞通道,输出缓冲区可用空间小于
     count,请求的字节序列数将不能完全传输到目标通道。
     * <p> This method does not modify this channel's position.  If the given
     * position is greater than the file's current size then no bytes are
     * transferred.  If the target channel has a position then bytes are
     * written starting at that position and then the position is incremented
     * by the number of bytes written.
     *此方法不会修改通道的位置。如果给的position大于文件大小,将不会有任何字节传输到
     目标通道。如果有任何字节写到目标通道,则目标通道position将会增长更新已写字节数量。
     * <p> This method is potentially much more efficient than a simple loop
     * that reads from this channel and writes to the target channel.  Many
     * operating systems can transfer bytes directly from the filesystem cache
     * to the target channel without actually copying them.  

     *此通道比简单的循环从本通道读取字节写到目标通道高效。许多操作系统可以在不拷贝字节的情况下,直接从
     文件系统的缓存中,传输字节到目标通道。
     * @param  position
     *         The position within the file at which the transfer is to begin;
     *         must be non-negative
     *
     * @param  count
     *         The maximum number of bytes to be transferred; must be
     *         non-negative
     *
     * @param  target
     *         The target channel
     *
     * @return  The number of bytes, possibly zero,
     *          that were actually transferred
     *返回实际传输的字节数,可能为0
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws  NonReadableChannelException
     *          If this channel was not opened for reading
     *本通道非以读模式打开
     * @throws  NonWritableChannelException
     *          If the target channel was not opened for writing
     *目标通道非以写模式打开
     * @throws  ClosedChannelException
     *          If either this channel or the target channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes either channel
     *          while the transfer is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread while the
     *          transfer is in progress, thereby closing both channels and
     *          setting the current thread's interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long transferTo(long position, long count,
                                    WritableByteChannel target)
        throws IOException;

    /**
     * Transfers bytes into this channel's file from the given readable byte
     * channel.
     *从指定的可读字节通道,读取字节序列,写到指定的通道文件
     *  An attempt is made to read up to <tt>count</tt> bytes from the
     * source channel and write them to this channel's file starting at the
     * given <tt>position</tt>.  An invocation of this method may or may not
     * transfer all of the requested bytes; whether or not it does so depends
     * upon the natures and states of the channels.  Fewer than the requested
     * number of bytes will be transferred if the source channel has fewer than
     * <tt>count</tt> bytes remaining, or if the source channel is non-blocking
     * and has fewer than <tt>count</tt> bytes immediately available in its
     * input buffer.
     *尝试从源通道的position位置读取count个字节,写到本通道文件。调用此方法也许会,也许不会
     传输所有请求的字节序列;具体是否全部传输依赖于通道状态和性质。如果源通道中,从
     position开始没有count个字节,或者源通道是一个非阻塞通道,输入缓冲区中的字节数小于
     count,请求的字节序列数将不能完全传输到本通道通道文件。
     * <p> This method does not modify this channel's position.  If the given
     * position is greater than the file's current size then no bytes are
     * transferred.  If the source channel has a position then bytes are read
     * starting at that position and then the position is incremented by the
     * number of bytes read.
     *此方法不会修改当前通道的位置。如果给的position大于文件大小,将不会有任何字节传输到
     目标通道。如果从源通道读取任何字节,则源通道position将会增长更新已读字节数量。
     * <p> This method is potentially much more efficient than a simple loop
     * that reads from the source channel and writes to this channel.  Many
     * operating systems can transfer bytes directly from the source channel
     * into the filesystem cache without actually copying them.  

     *此通道比简单的循环从源通道读取字节写到本通道高效。许多操作系统可以在不拷贝字节的情况下,直接从
     源通道,传输到文件系统的缓存中。
     * @param  src
     *         The source channel
     *
     * @param  position
     *         The position within the file at which the transfer is to begin;
     *         must be non-negative
     *
     * @param  count
     *         The maximum number of bytes to be transferred; must be
     *         non-negative
     *
     * @return  The number of bytes, possibly zero,
     *          that were actually transferred
     *实际传输字节数,可能为0
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws  NonReadableChannelException
     *          If the source channel was not opened for reading
     *源通道非以读模式打开
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *本通道非以写模式打开
     * @throws  ClosedChannelException
     *          If either this channel or the source channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes either channel
     *          while the transfer is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread while the
     *          transfer is in progress, thereby closing both channels and
     *          setting the current thread's interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long transferFrom(ReadableByteChannel src,
                                      long position, long count)
        throws IOException;

    /**
     * Reads a sequence of bytes from this channel into the given buffer,
     * starting at the given file position.
     *从当前通道文件的给定位置,读取字节序列到buffer中
     *  This method works in the same manner as the {@link
     * #read(ByteBuffer)} method, except that bytes are read starting at the
     * given file position rather than at the channel's current position.  This
     * method does not modify this channel's position.  If the given position
     * is greater than the file's current size then no bytes are read.  

     *此方法与read(ByteBuffer)基本相同,不同的是,读取文件的位置是从给定的position,而不是当前文件的
     position。此方法不会修改通道的位置。如果给定的位置大于当前文件大小,没有字节可读。
     * @param  dst
     *         The buffer into which bytes are to be transferred
     *
     * @param  position
     *         The file position at which the transfer is to begin;
     *         must be non-negative
     *
     * @return  The number of bytes read, possibly zero, or <tt>-1</tt> if the
     *          given position is greater than or equal to the file's current
     *          size
     *实际读取的字节数量,也许为0,如果给定的位置大于或等于文件当前大小,则返回-1
     * @throws  IllegalArgumentException
     *          If the position is negative
     *
     * @throws  NonReadableChannelException
     *          If this channel was not opened for reading
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the read operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the read operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract int read(ByteBuffer dst, long position) throws IOException;

    /**
     * Writes a sequence of bytes to this channel from the given buffer,
     * starting at the given file position.
     *从本通道的position位置开始写从buffer中读写字节序列。
     *  This method works in the same manner as the {@link
     * #write(ByteBuffer)} method, except that bytes are written starting at
     * the given file position rather than at the channel's current position.
     * This method does not modify this channel's position.  If the given
     * position is greater than the file's current size then the file will be
     * grown to accommodate the new bytes; the values of any bytes between the
     * previous end-of-file and the newly-written bytes are unspecified.  

     *此方法与#write(ByteBuffer)基本相同,不同的是,是从给定的position位置,写字节序列,而不是当前文件的
     position。此方法不会修改通道的位置。如果给定的position位置大于文件size,写字节,将会引起
     文件的增长,在先前文件的末尾和新写的字节序列之间的字节序列值是不确定的。
     * @param  src
     *         The buffer from which bytes are to be transferred
     *
     * @param  position
     *         The file position at which the transfer is to begin;
     *         must be non-negative
     *
     * @return  The number of bytes written, possibly zero
     *写的字节数可能为0
     * @throws  IllegalArgumentException
     *          If the position is negative
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the write operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the write operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract int write(ByteBuffer src, long position) throws IOException;


    // -- Memory-mapped buffers --
   //内存映射缓存
    /**
     * A typesafe enumeration for file-mapping modes.
     *文件映射模式的类型安全枚举类
     * @since 1.4
     *
     * @see java.nio.channels.FileChannel#map
     */
    public static class MapMode {

        /**
         * Mode for a read-only mapping.
	 只读映射模式
         */
        public static final MapMode READ_ONLY
            = new MapMode("READ_ONLY");

        /**
         * Mode for a read/write mapping.
	 可读写模式映射
         */
        public static final MapMode READ_WRITE
            = new MapMode("READ_WRITE");

        /**
         * Mode for a private (copy-on-write) mapping.
	 私有映射模式(写拷贝)
         */
        public static final MapMode PRIVATE
            = new MapMode("PRIVATE");

        private final String name;

        private MapMode(String name) {
            this.name = name;
        }

        /**
         * Returns a string describing this file-mapping mode.
         *
         * @return  A descriptive string
         */
        public String toString() {
            return name;
        }

    }

    /**
     * Maps a region of this channel's file directly into memory.
     *直接映射文件的一个region到内存中
     *  A region of a file may be mapped into memory in one of three modes:
     * 

     *一个文件region可以以一下三种模式映射到内存中:
     * <ul type=disc>
     *
     *   <li> <i>Read-only:</i> Any attempt to modify the resulting buffer
     *   will cause a {@link java.nio.ReadOnlyBufferException} to be thrown.
     *   ({@link MapMode#READ_ONLY MapMode.READ_ONLY}) 
</li>
     *Read-only:任何尝试修改返回buffer内容讲引起ReadOnlyBufferException,MapMode#READ_ONLY;
     *   <li> <i>Read/write:</i> Changes made to the resulting buffer will
     *   eventually be propagated to the file; they may or may not be made
     *   visible to other programs that have mapped the same file.  ({@link
     *   MapMode#READ_WRITE MapMode.READ_WRITE}) 
</li>
     *Read/write,任何对结果buffer的修改,会反应到file中,他们也许会,也许不会
     对文件的其他内存映射,MapMode#READ_WRITE;
     *   <li> <i>Private:</i> Changes made to the resulting buffer will not
     *   be propagated to the file and will not be visible to other programs
     *   that have mapped the same file; instead, they will cause private
     *   copies of the modified portions of the buffer to be created.  ({@link
     *   MapMode#PRIVATE MapMode.PRIVATE}) 
</li>
     *Private:任何对结果buffer的修改,不会反应到file中,他们也不会
     对文件的其他内存映射,而是,产生一个缓存修改部分的copy,MapMode#PRIVATE。
     * </ul>
     *
     *  For a read-only mapping, this channel must have been opened for
     * reading; for a read/write or private mapping, this channel must have
     * been opened for both reading and writing.
     *在只读映射模式下,通道必须已经被以只读模式打开;对于读写和私有映射模式,
     通道必须以读写模式打开。
     * <p> The {@link MappedByteBuffer <i>mapped byte buffer</i>}
     * returned by this method will have a position of zero and a limit and
     * capacity of <tt>size</tt>; its mark will be undefined.  The buffer and
     * the mapping that it represents will remain valid until the buffer itself
     * is garbage-collected.
     *方法返回的MappedByteBuffer,position为0,limit为容量size;但mark标志位是不确定的。
     在buffer被垃圾回收器回收之前,缓冲和相应的映射仍有效。
     * <p> A mapping, once established, is not dependent upon the file channel
     * that was used to create it.  Closing the channel, in particular, has no
     * effect upon the validity of the mapping.
     *映射一旦创建,将不会依赖于创建它的文件通道。关闭通道,在一些特殊情况下,
     将不会影响到映射的有效性。
     * <p> Many of the details of memory-mapped files are inherently dependent
     * upon the underlying operating system and are therefore unspecified.  The
     * behavior of this method when the requested region is not completely
     * contained within this channel's file is unspecified.  Whether changes
     * made to the content or size of the underlying file, by this program or
     * another, are propagated to the buffer is unspecified.  The rate at which
     * changes to the buffer are propagated to the file is unspecified.
     *许多内存映射文件的具体属性或信息要依赖于底层操作系统,因此是不确定的。当请求
     的region不完全在通道文件中,此方法的行为是不确定的。无论是否通道程序或其他改变底层文件的内容和size,
     会不会反应到buffer,是不确定的。对buffer改变反应到文件的频率是确定的。
     * <p> For most operating systems, mapping a file into memory is more
     * expensive than reading or writing a few tens of kilobytes of data via
     * the usual {@link #read read} and {@link #write write} methods.  From the
     * standpoint of performance it is generally only worth mapping relatively
     * large files into memory.  

     *对于大多数的操作系统,映射文件到内存比通过#read和#write方法读写几十kb要消耗更多。
     从性能这点来说,通常情况下,映射相对较大的文件到内存,在性能上是值得的。即对于文件
     直接进行读写,对于大文件,可以将文件映射到内存中,可以提高性能。
     * @param  mode
     *         One of the constants {@link MapMode#READ_ONLY READ_ONLY}, {@link
     *         MapMode#READ_WRITE READ_WRITE}, or {@link MapMode#PRIVATE
     *         PRIVATE} defined in the {@link MapMode} class, according to
     *         whether the file is to be mapped read-only, read/write, or
     *         privately (copy-on-write), respectively
     *
     * @param  position
     *         The position within the file at which the mapped region
     *         is to start; must be non-negative
     *
     * @param  size
     *         The size of the region to be mapped; must be non-negative and
     *         no greater than {@link java.lang.Integer#MAX_VALUE}
     *
     * @return  The mapped byte buffer
     *
     * @throws NonReadableChannelException
     *         If the <tt>mode</tt> is {@link MapMode#READ_ONLY READ_ONLY} but
     *         this channel was not opened for reading
     *
     * @throws NonWritableChannelException
     *         If the <tt>mode</tt> is {@link MapMode#READ_WRITE READ_WRITE} or
     *         {@link MapMode#PRIVATE PRIVATE} but this channel was not opened
     *         for both reading and writing
     *
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws IOException
     *         If some other I/O error occurs
     *
     * @see java.nio.channels.FileChannel.MapMode
     * @see java.nio.MappedByteBuffer
     */
    public abstract MappedByteBuffer map(MapMode mode,
                                         long position, long size)
        throws IOException;


    // -- Locks --
    //锁部分
    /**
     * Acquires a lock on the given region of this channel's file.
     *尝试对文件的给定region加锁
     *  An invocation of this method will block until the region can be
     * locked, this channel is closed, or the invoking thread is interrupted,
     * whichever comes first.
     *调用此方法,将会阻塞到,文件region可以被lock,或通道关闭,或调用此方法的线程中断,
     无论那个条件先发生。
     * <p> If this channel is closed by another thread during an invocation of
     * this method then an {@link AsynchronousCloseException} will be thrown.
     *如果在调用方法期间,其他线程关闭通道,则抛出AsynchronousCloseException。
     * <p> If the invoking thread is interrupted while waiting to acquire the
     * lock then its interrupt status will be set and a {@link
     * FileLockInterruptionException} will be thrown.  If the invoker's
     * interrupt status is set when this method is invoked then that exception
     * will be thrown immediately; the thread's interrupt status will not be
     * changed.
     *如果当等待获取锁的情况下,调用线程中断,将会设置线程中断位,并抛出FileLockInterruptionException。
     如果调用的中断状态为被设置,则调用方法将立刻抛出异常,线程中断位不为改变。
     * <p> The region specified by the <tt>position</tt> and <tt>size</tt>
     * parameters need not be contained within, or even overlap, the actual
     * underlying file.  Lock regions are fixed in size; if a locked region
     * initially contains the end of the file and the file grows beyond the
     * region then the new portion of the file will not be covered by the lock.
     * If a file is expected to grow in size and a lock on the entire file is
     * required then a region starting at zero, and no smaller than the
     * expected maximum size of the file, should be locked.  The zero-argument
     * {@link #lock()} method simply locks a region of size {@link
     * Long#MAX_VALUE}.
     *position和size描述的region不需要在实际底层文件中存在或部分存在;如果一个
     被锁的region在初始化时包含文件的末尾,稳健增长超过region的部分数据,lock并
     不会锁住。如果在文件增长是锁住整个文件,则region可以从0开始,不小于期望文件大小的size。
     零参数#lock方法,锁住region的size为Long#MAX_VALUE
     * <p> Some operating systems do not support shared locks, in which case a
     * request for a shared lock is automatically converted into a request for
     * an exclusive lock.  Whether the newly-acquired lock is shared or
     * exclusive may be tested by invoking the resulting lock object's {@link
     * FileLock#isShared() isShared} method.
     *一些操作系统不支持共享锁,在这种情况下,请求一个共享锁,将自动转化为互质锁。
     我们可以通道FileLock#isShared方法判断获取的是共享锁还是互斥锁。
     * <p> File locks are held on behalf of the entire Java virtual machine.
     * They are not suitable for controlling access to a file by multiple
     * threads within the same virtual machine.  

     *文件锁被虚拟机自己持有。在同一个虚拟机中,不适合通过多线程访问文件。
     * @param  position
     *         The position at which the locked region is to start; must be
     *         non-negative
     *
     * @param  size 文件region的size
     *         The size of the locked region; must be non-negative, and the sum
     *         <tt>position</tt> + <tt>size</tt> must be non-negative
     *
     * @param  shared,是否共享模式,true共享
     *         <tt>true</tt> to request a shared lock, in which case this
     *         channel must be open for reading (and possibly writing);
     *         <tt>false</tt> to request an exclusive lock, in which case this
     *         channel must be open for writing (and possibly reading)
     *
     * @return  A lock object representing the newly-acquired lock
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on the parameters do not hold
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel while the invoking
     *          thread is blocked in this method
     *
     * @throws  FileLockInterruptionException
     *          If the invoking thread is interrupted while blocked in this
     *          method
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region
     如果虚拟机已经持有请求文件region的锁,如果其他线程已经阻塞,尝试获取锁。
     *
     * @throws  NonReadableChannelException
     *          If <tt>shared</tt> is <tt>true</tt> this channel was not
     *          opened for reading
     *
     * @throws  NonWritableChannelException
     *          If <tt>shared</tt> is <tt>false</tt> but this channel was not
     *          opened for writing
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #tryLock()
     * @see     #tryLock(long,long,boolean)
     */
    public abstract FileLock lock(long position, long size, boolean shared)
        throws IOException;

    /**
     * Acquires an exclusive lock on this channel's file.
     *获取通道文件的互质锁
     *  An invocation of this method of the form <tt>fc.lock()</tt> behaves
     * in exactly the same way as the invocation
     *调用fc.lock()与lock(0L, Long.MAX_VALUE, false) 方法基本相同
     * <pre>
     *     fc.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false) </pre>
     *
     * @return  A lock object representing the newly-acquired lock
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel while the invoking
     *          thread is blocked in this method
     *
     * @throws  FileLockInterruptionException
     *          If the invoking thread is interrupted while blocked in this
     *          method
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region of the same file
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock(long,long,boolean)
     * @see     #tryLock()
     * @see     #tryLock(long,long,boolean)
     */
    public final FileLock lock() throws IOException {
        return lock(0L, Long.MAX_VALUE, false);
    }

    /**
     * Attempts to acquire a lock on the given region of this channel's file.
     *尝试获取文件给定region的锁
     * <p> This method does not block.  An invocation always returns
     * immediately, either having acquired a lock on the requested region or
     * having failed to do so.  If it fails to acquire a lock because an
     * overlapping lock is held by another program then it returns
     * <tt>null</tt>.  If it fails to acquire a lock for any other reason then
     * an appropriate exception is thrown.
     *此方法不会阻塞。调用方法将立刻返回,或者尝试获取请求文件region已经失败。
     如果因为虚拟机持有文件region的锁,而获取失败,则返回null,如果其他原因,则抛出异常。
     * <p> The region specified by the <tt>position</tt> and <tt>size</tt>
     * parameters need not be contained within, or even overlap, the actual
     * underlying file.  Lock regions are fixed in size; if a locked region
     * initially contains the end of the file and the file grows beyond the
     * region then the new portion of the file will not be covered by the lock.
     * If a file is expected to grow in size and a lock on the entire file is
     * required then a region starting at zero, and no smaller than the
     * expected maximum size of the file, should be locked.  The zero-argument
     * {@link #tryLock()} method simply locks a region of size {@link
     * Long#MAX_VALUE}.
     *position和size描述的region不需要在实际底层文件中存在或部分存在;如果一个
     被锁的region在初始化时包含文件的末尾,稳健增长超过region的部分数据,lock并
     不会锁住。如果在文件增长是锁住整个文件,则region可以从0开始,不小于期望文件大小的size。
     零参数#lock方法,锁住region的size为Long#MAX_VALUE
     * <p> Some operating systems do not support shared locks, in which case a
     * request for a shared lock is automatically converted into a request for
     * an exclusive lock.  Whether the newly-acquired lock is shared or
     * exclusive may be tested by invoking the resulting lock object's {@link
     * FileLock#isShared() isShared} method.
      一些操作系统不支持共享锁,在这种情况下,请求一个共享锁,将自动转化为互质锁。
     我们可以通道FileLock#isShared方法判断获取的是共享锁还是互斥锁。
     *
     * <p> File locks are held on behalf of the entire Java virtual machine.
     * They are not suitable for controlling access to a file by multiple
     * threads within the same virtual machine.  

     *文件锁被虚拟机自己持有。在同一个虚拟机中,不适合通过多线程访问文件。
     * @param  position
     *         The position at which the locked region is to start; must be
     *         non-negative
     *
     * @param  size
     *         The size of the locked region; must be non-negative, and the sum
     *         <tt>position</tt> + <tt>size</tt> must be non-negative
     *
     * @param  shared
     *         <tt>true</tt> to request a shared lock,
     *         <tt>false</tt> to request an exclusive lock
     *
     * @return  A lock object representing the newly-acquired lock,
     *          or <tt>null</tt> if the lock could not be acquired
     *          because another program holds an overlapping lock
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on the parameters do not hold
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region of the same file
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #lock(long,long,boolean)
     * @see     #tryLock()
     */
    public abstract FileLock tryLock(long position, long size, boolean shared)
        throws IOException;

    /**
     * Attempts to acquire an exclusive lock on this channel's file.
     *
     * <p> An invocation of this method of the form <tt>fc.tryLock()</tt>
     * behaves in exactly the same way as the invocation
     *
     * <pre>
     *     fc.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre>
     *
     * @return  A lock object representing the newly-acquired lock,
     *          or <tt>null</tt> if the lock could not be acquired
     *          because another program holds an overlapping lock
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #lock(long,long,boolean)
     * @see     #tryLock(long,long,boolean)
     */
    public final FileLock tryLock() throws IOException {
        return tryLock(0L, Long.MAX_VALUE, false);
    }

}


附:
//StandardOpenOption,文件打开选项,前面FileChannle构造方法,已经说,这里不再说
package java.nio.file;

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

public enum StandardOpenOption implements OpenOption {
    /**
     * Open for read access.
     */
    READ,

    /**
     * Open for write access.
     */
    WRITE,

    /**
     * If the file is opened for {@link #WRITE} access then bytes will be written
     * to the end of the file rather than the beginning.
     *
     * <p> If the file is opened for write access by other programs, then it
     * is file system specific if writing to the end of the file is atomic.
     */
    APPEND,

    /**
     * If the file already exists and it is opened for {@link #WRITE}
     * access, then its length is truncated to 0. This option is ignored
     * if the file is opened only for {@link #READ} access.
     */
    TRUNCATE_EXISTING,

    /**
     * Create a new file if it does not exist.
     * This option is ignored if the {@link #CREATE_NEW} option is also set.
     * The check for the existence of the file and the creation of the file
     * if it does not exist is atomic with respect to other file system
     * operations.
     */
    CREATE,

    /**
     * Create a new file, failing if the file already exists.
     * The check for the existence of the file and the creation of the file
     * if it does not exist is atomic with respect to other file system
     * operations.
     */
    CREATE_NEW,

    /**
     * Delete on close. When this option is present then the implementation
     * makes a [i]best effort[/i] attempt to delete the file when closed
     * by the appropriate {@code close} method. If the {@code close} method is
     * not invoked then a [i]best effort[/i] attempt is made to delete the
     * file when the Java virtual machine terminates (either normally, as
     * defined by the Java Language Specification, or where possible, abnormally).
     * This option is primarily intended for use with [i]work files[/i] that
     * are used solely by a single instance of the Java virtual machine. This
     * option is not recommended for use when opening files that are open
     * concurrently by other entities. Many of the details as to when and how
     * the file is deleted are implementation specific and therefore not
     * specified. In particular, an implementation may be unable to guarantee
     * that it deletes the expected file when replaced by an attacker while the
     * file is open. Consequently, security sensitive applications should take
     * care when using this option.
     *
     * <p> For security reasons, this option may imply the {@link
     * LinkOption#NOFOLLOW_LINKS} option. In other words, if the option is present
     * when opening an existing file that is a symbolic link then it may fail
     * (by throwing {@link java.io.IOException}).
     */
    DELETE_ON_CLOSE,

    /**
     * Sparse file. When used with the {@link #CREATE_NEW} option then this
     * option provides a [i]hint[/i] that the new file will be sparse. The
     * option is ignored when the file system does not support the creation of
     * sparse files.
     */
    SPARSE,

    /**
     * Requires that every update to the file's content or metadata be written
     * synchronously to the underlying storage device.
     *
     * @see [url=package-summary.html#integrity]Synchronized I/O file integrity[/url]
     */
    SYNC,

    /**
     * Requires that every update to the file's content be written
     * synchronously to the underlying storage device.
     *
     * @see [url=package-summary.html#integrity]Synchronized I/O file integrity[/url]
     */
    DSYNC;
}

//OpenOption
package java.nio.file;

/**
 * An object that configures how to open or create a file.
 *配置如果打开或创建一个文件,在如下方法中使用
 * <p> Objects of this type are used by methods such as {@link
 * Files#newOutputStream(Path,OpenOption[]) newOutputStream}, {@link
 * Files#newByteChannel newByteChannel}, {@link
 * java.nio.channels.FileChannel#open FileChannel.open}, and {@link
 * java.nio.channels.AsynchronousFileChannel#open AsynchronousFileChannel.open}
 * when opening or creating a file.
 *
 * <p> The {@link StandardOpenOption} enumeration type defines the
 * <i>standard</i> options.
 *
 * @since 1.7
 */

public interface OpenOption {
}

//FileAttribute

package java.nio.file.attribute;

/**
 * An object that encapsulates the value of a file attribute that can be set
 * atomically when creating a new file or directory by invoking the {@link
 * java.nio.file.Files#createFile createFile} or {@link
 * java.nio.file.Files#createDirectory createDirectory} methods.
 *FileAttribute封装了文件属性值,调用Files#createFile和Files#createDirectory,创建文件或目录 
 时,自动设置文件属性。
 * @param <T> The type of the file attribute value
 *
 * @since 1.7
 * @see PosixFilePermissions#asFileAttribute
 */

public interface FileAttribute<T> {
    /**
     * Returns the attribute name.
     */
    String name();

    /**
     * Returns the attribute value.
     */
    T value();
}

//FileLock
public abstract class FileLock implements AutoCloseable {
    private final Channel channel;//文件关联通道
    private final long position;//锁文件region的开始位置
    private final long size;//文件锁,锁住文件region的大小
    private final boolean shared;//是否共享模式
    ...
}

//AutoCloseable
package java.lang;

/**
 * A resource that must be closed when it is no longer needed.
 *
 * @author Josh Bloch
 * @since 1.7
 */
public interface AutoCloseable {
    /**
     * Closes this resource, relinquishing any underlying resources.
     * This method is invoked automatically on objects managed by the
     * {@code try}-with-resources statement.
     *关闭资源,放弃任何关联的底层资源。此方法将自动使用try语句块管理
     资源对象。
     * <p>While this interface method is declared to throw {@code
     * Exception}, implementers are [i]strongly[/i] encouraged to
     * declare concrete implementations of the {@code close} method to
     * throw more specific exceptions, or to throw no exception at all
     * if the close operation cannot fail.
     *此接口方法声明抛出异常,具体的实现强烈建议抛出具体的异常,或如果关闭
     操作没失败,不抛出。
     * <p>[i]Implementers of this interface are also strongly advised
     * to not have the {@code close} method throw {@link
     * InterruptedException}.[/i]
     * 具体的实现,不建议抛出中断异常。
     * This exception interacts with a thread's interrupted status,
     * and runtime misbehavior is likely to occur if an {@code
     * InterruptedException} is {@linkplain Throwable#addSuppressed
     * suppressed}.
     *如果一个中断异常被Throwable#addSuppressed抑制,与线程中断位相关的
     异常和运行时异常有可能发生。
     * More generally, if it would cause problems for an
     * exception to be suppressed, the {@code AutoCloseable.close}
     * method should not throw it.
     *在大多数情况下,如果引起的异常被吃掉,AutoCloseable.close将不会抛出。
     * <p>Note that unlike the {@link java.io.Closeable#close close}
     * method of {@link java.io.Closeable}, this {@code close} method
     * is [i]not[/i] required to be idempotent.  In other words,
     * calling this {@code close} method more than once may have some
     * visible side effect, unlike {@code Closeable.close} which is
     * required to have no effect if called more than once.
     *不像java.io.Closeable#close方法,close不需要幂等的。换句话,多次调用
     close方法,将会有一些副作用,不像Closeable.close,如果调用多次,没有任何影响。
     * However, implementers of this interface are strongly encouraged
     * to make their {@code close} methods idempotent.
     *接口的实现,强烈建议调用方法的实现是幂等的,即多次调用,没有任何影响。
     * @throws Exception if this resource cannot be closed
     */
    void close() throws Exception;
}
0
1
分享到:
评论

相关推荐

    java使用多线程读取超大文件

    在这个工具类中,我们定义了几个重要的变量:`bufSize`是缓冲区的大小,`key`是换行符,`lineNum`是当前行数,`encode`是文件编码,`readerListener`是业务逻辑监听器。 接下来,我们需要实现`getStartNum`方法,该...

    java+sql server项目之科帮网计算机配件报价系统源代码.zip

    sql server+java项目之科帮网计算机配件报价系统源代码

    【java毕业设计】智慧社区老人健康监测门户.zip

    有java环境就可以运行起来 ,zip里包含源码+论文+PPT, 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7及以上 数据库工具:Navicat11及以上 开发软件:eclipse/idea Maven包:Maven3.3及以上

    【java毕业设计】智慧社区心理咨询平台(源代码+论文+PPT模板).zip

    zip里包含源码+论文+PPT,有java环境就可以运行起来 ,功能说明: 文档开篇阐述了随着计算机技术、通信技术和网络技术的快速发展,智慧社区门户网站的建设成为了可能,并被视为21世纪信息产业的主要发展方向之一 强调了网络信息管理技术、数字化处理技术和数字式信息资源建设在国际竞争中的重要性。 指出了智慧社区门户网站系统的编程语言为Java,数据库为MYSQL,并实现了新闻资讯、社区共享、在线影院等功能。 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。

    计算机系统基础实验LinkLab实验及解答:深入理解ELF文件与链接过程

    内容概要:本文档详细介绍了LinkLab实验的五个阶段,涵盖了ELF文件的组成、符号表的理解、代码节与重定位位置的修改等内容。每个阶段都有具体的实验要求和步骤,帮助学生理解链接的基本概念和链接过程中涉及的各项技术细节。 适合人群:计算机科学专业的本科生,特别是正在修读《计算机系统基础》课程的学生。 使用场景及目标:① 通过实际操作加深对链接过程和ELF文件的理解;② 掌握使用readelf、objdump和hexedit等工具的技巧;③ 实现特定输出以验证实验结果。 阅读建议:实验过程中的每个阶段都有明确的目标和提示,学生应按照步骤逐步操作,并结合反汇编代码和二进制编辑工具进行实践。在完成每个阶段的实验后,应及时记录实验结果和遇到的问题,以便于总结和反思。

    基于关键词的历时百度搜索指数自动采集资料齐全+详细文档+高分项目+源码.zip

    【资源说明】 基于关键词的历时百度搜索指数自动采集资料齐全+详细文档+高分项目+源码.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    用C语言写出一个简单的圣诞树,让你的朋友们体验一下程序员的浪漫,点开即令哦!

    第一次发文的小白,解释的不好,各位大佬勿怪哦

    免费下载:Hilma af Klint a Biography (Julia Voss)_tFy2T.zip

    免费下载:Hilma af Klint a Biography (Julia Voss)_tFy2T.zip

    屏幕截图 2024-12-21 172527.png

    屏幕截图 2024-12-21 172527

    2024级涉外护理7班马天爱劳动实践总结1.docx

    2024级涉外护理7班马天爱劳动实践总结1.docx

    IndexOutOfBoundsException(解决方案).md

    IndexOutOfBoundsException(解决方案)

    【java毕业设计】智慧社区垃圾分类门户.zip

    有java环境就可以运行起来 ,zip里包含源码+论文+PPT, 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7及以上 数据库工具:Navicat11及以上 开发软件:eclipse/idea Maven包:Maven3.3及以上

    【java毕业设计】智慧社区网端门户(源代码+论文+PPT模板).zip

    有java环境就可以运行起来 ,zip里包含源码+论文+PPT, 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7及以上 数据库工具:Navicat11及以上 开发软件:eclipse/idea Maven包:Maven3.3及以上

    【java毕业设计】智慧社区智慧养老照护系统(源代码+论文+PPT模板).zip

    zip里包含源码+论文+PPT,有java环境就可以运行起来 ,功能说明: 文档开篇阐述了随着计算机技术、通信技术和网络技术的快速发展,智慧社区门户网站的建设成为了可能,并被视为21世纪信息产业的主要发展方向之一 强调了网络信息管理技术、数字化处理技术和数字式信息资源建设在国际竞争中的重要性。 指出了智慧社区门户网站系统的编程语言为Java,数据库为MYSQL,并实现了新闻资讯、社区共享、在线影院等功能。 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。

    Delphi 12 控件之DevExpressVCLProductDemos-24.2.3.exe

    DevExpressVCLProductDemos-24.2.3.exe

    计算机语言学中并查集数据结构的C++实现

    欢迎下载

    【java毕业设计】智慧社区养老服务平台.zip

    有java环境就可以运行起来 ,zip里包含源码+论文+PPT, 系统设计与功能: 文档详细描述了系统的后台管理功能,包括系统管理模块、新闻资讯管理模块、公告管理模块、社区影院管理模块、会员上传下载管理模块以及留言管理模块。 系统管理模块:允许管理员重新设置密码,记录登录日志,确保系统安全。 新闻资讯管理模块:实现新闻资讯的添加、删除、修改,确保主页新闻部分始终显示最新的文章。 公告管理模块:类似于新闻资讯管理,但专注于主页公告的后台管理。 社区影院管理模块:管理所有视频的添加、删除、修改,包括影片名、导演、主演、片长等信息。 会员上传下载管理模块:审核与删除会员上传的文件。 留言管理模块:回复与删除所有留言,确保系统内的留言得到及时处理。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7及以上 数据库工具:Navicat11及以上 开发软件:eclipse/idea Maven包:Maven3.3及以上

    小米15pro工程固件 可以用于修改参数 修复tee损坏 修复底层分区 会用的下载

    资源描述: 机型代码:haotian 1-----工程固件可以用于修改参数 开启diag端口。可以用于修复tee损坏以及修复底层分区。 2-----此固件是完整官方。不是第三方打包。请知悉 3-----此固件可以解锁bl后fast模式刷写。也可以底层深刷。也可以编程器写入 4-----请会用此固件 了解工程固件常识以及会用的朋友下载。 5-----个别高版本深刷需要授权才可以刷入。需要自己会刷写。 6------资源有可复制性。下载后不支持退。请考虑清楚在下载哦 工程资源常识可以参考博文:https://blog.csdn.net/u011283906/article/details/141815378 了解基本

    JSP论文格式化系统_——后台模块的设计与实现(源代码+论文)(2024gk).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    html+css网页设计 美食 蛋糕美食7个页面

    预览地址:https://blog.csdn.net/qq_42431718/article/details/144633992 html+css网页设计 美食 蛋糕美食7个页面

Global site tag (gtag.js) - Google Analytics