流与文件
-
流
在Java API中,可以从其中读入一个字节序列的对象称为输入流,可以向其中写入一个字节序列的对象称为输出流。抽象类
InputStream
和OutputStream
构成了I/O类层次机构的基础。因为面向字节的流不便于处理以Unicode形式存储的信息(Unicode中每个字符都是由多个字节构成的),所以从抽象类
Reader
和Writer
中继承出了一个专门处理Unicode字符的单独的类层次结构。 -
InputStream
、OutputStream
、Reader
和Writer
-
InputStream
:InputStream的所有方法InputStream
有一个abstract int read()
抽象方法,该方法读入一个字节并返回这个字节,或者在遇到输入源结尾时返回-1
。在设计具体的输入流类时,必须覆盖这个方法以提供实用的功能。InputStream
还有两个非抽象的read
方法,这两个方法都会调用抽象的read
方法。 -
继承结构:
InputStream继承结构
除了在java.io
包中有FilterInputStream
子类外,其它包中也有,FilterInputStream
的所有直接子类有:image -
OutputStream
:OutputStream的所有方法
与InputStream
类似,OutputStream
定义了abstract int write()
抽象方法,用于向该输出流写出一个字节。 -
继承结构:
`OutputStream`继承结构FilterOutputStream
的直接子类:
image -
Reader
:Reader的所有方法 -
继承结构:
image -
Writer
:Writer的所有方法 -
继承结构:
image
当完成对流的读写后,都应该调用
close
方法关闭流。否则系统资源的不到释放,如果使用了缓冲区,对于缓冲区最后一个包的读写也有影响。4个抽象类都实现了
Closeable
接口,该接口扩展了java.lang.AutoCloseable
接口,所以4个抽象类都可以使用try-with-resource
语句。 -
-
以文本方式输出
我们可以使用
PrintWriter
输出文本,BufferedReader
读入文本。try(PrintWriter printWriter = new PrintWriter("test2.txt"); BufferedReader bufferedReader = new BufferedReader(new FileReader("test2.txt"))){ printWriter.println("this is "); printWriter.println("文本输出"); printWriter.flush(); while (bufferedReader.ready()) log.info(bufferedReader.readLine()); }catch (Exception e){ e.printStackTrace(); }
-
字符集
在JavaSE 1.4中引入的
Charset
类统一提供了对字符集的转换。它有一下几个主要方法:
//返回一个指定字符集类型对象 static Charset forName(String charsetName); //返回该字符集的所有别名 Set<String> aliases(); //获取当前支持的所有字符集 public static SortedMap<String,Charset> availableCharsets(); //将字符序列编码为指定编码的字节序列 ByteBuffer encode(CharBuffer cb); //将字符串编码为指定编码的字节序列 ByteBuffer encode(String str); //将指定的字节序列解码,唯一的解码方法 CharBuffer decode(ByteBuffer bb)
解码指定字节序列时,需要有字节缓冲区,使用
ByteBuffer
的wrap
方法将一个字节数组转换为一个字节缓冲区。static ByteBuffer wrap(byte[] array, int offset, int length); static ByteBuffer wrap(byte[] array); //返回这个缓冲区所管理的字节数组 byte[] array();
java.nio.CharBuffer
://返回这个字符缓冲区管理的字符数组 char[] array(); //返回给定索引出的码元 char charAt(int index); //返回由这个缓冲区管理的码元所构成的字符串 String toString();
一个完整的编码解码过程:
Charset charSet = Charset.forName("utf-8"); String text = "this is a 文本"; //编码 ByteBuffer byteBuffer = charSet.encode(text); byte[] encodeResult = byteBuffer.array(); //解码 //解码时,需要将字节缓冲区 byteBuffer = ByteBuffer.wrap(encodeResult); CharBuffer charBuffer = charset.decode(byteBuffer); String decodeResult = charBuffer.toString();
-
读写二进制数据
DataOutput
接口的方法来实现以二进制的形式写Java的基本类型数据。DataOutput定义的方法如
writeInt
总是将一个整数写出为4个字节长度的二进制数量值,WriteDouble
总是将一个double
值写出为8字节的二进制文件。这样产生的结果就是:总是对于给定类型的每一个值,所需的空间都是相同的。并且将其读回也比解析更快。DataOutputStream
实现了DataOutput
接口DataInput
接口定义了读入二进制数据的方法:DataInput定义的方法DataInputStream
实现了该接口。 -
随机读写文件
RandomAccessFile
类提供的方法可以帮助我们随机读写文件内容。这个类的构造器的第二个参数用于指定访问模式,
r
/rw
(只读/读写)RandomAccessFile in = new RandomAccessFile("data.dat","r");//只读 RandomAccessFile out = new RandomAccessFile("data.dat","rw");//可读写
RandomAccessFile
实现了DataInput
和DataOutput
两个接口,所以这类可以用来读写二进制数据。另外他还有关于文件指针方法://获取文件指针的位置,指针从0开始,最大为文件所包含的字节总数 long getFilePointer(); //将指针置于文件指定的位置 void seek(long pos);
因为
DataOutput
写出的每个类型数据长度固定,在加上随机访问的特性,使用RandomAccessFile
类来帮助我们将信息存储为二进制文件是一个很好的选择。 -
ZIP文档
ZIP文档一压缩格式存储了一个或多个文件,每个ZIP文档都有一个头,包含诸如每个文件名字和所使用的 压缩方法等信息。
在Java中,使用
ZipOutputStream
来读入ZIP文档://创建文件输出流 FileOutputStream fileOutputStream = new FileOutputStream("zipfile.zip"); ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream); //创建压缩文件项 ZipEntry zipEntry = new ZipEntry("text.txt"); ZipEntry zipEntry1 = new ZipEntry("text2.txt"); //写入第一个文件项 zipOutputStream.putNextEntry(zipEntry); //向文件项中写入内容 String context = "压缩文件text1的内容111"; zipOutputStream.write(Util.encode(context,"utf-8")); //非必须调用 //zipOutputStream.closeEntry(); //写入下一个文件项,必须调用这个方法,不然无法写入第二个文件项中 zipOutputStream.putNextEntry(zipEntry1); context = "压缩文件text2的内容222"; zipOutputStream.write(Util.encode(context,"utf-8")); //关闭流 zipOutputStream.close(); fileOutputStream.close();
使用
ZipInputStream
读入Zip文档://创建输入流 FileInputStream fileInputStream = new FileInputStream(("zipfile.zip")); ZipInputStream zipInputStream = new ZipInputStream(fileInputStream); ZipEntry zipEntry; while((zipEntry = zipInputStream.getNextEntry())!= null){ //检查文件项信息 Util.getLogger().info("file name : " + zipEntry.getName()); //读文件内容 byte[] content = new byte[100]; zipInputStream.read(content); Util.getLogger().info(Util.decode(content,"utf-8")); //非必须调用 //zipInputStream.closeEntry(); }
-
Path
接口An object that may be used to locate a file in a file system. It will typically represent a system dependent file path.
Path
表示的是一个目录名序列,其后还还可以跟着一个文件名。/** * 通过Pahts类的get方法来得到一个Path的实例 * Paths.get方法可以接受多个字符串,并将它们用默认的文件系统路径分隔符链接起来。 * 类Unix文件系统是'/',windows是'\' */ Path path = Paths.get("/home","lrz");
Path
有许多操作文件路径的方法:API -
Files
类This class consists exclusively of static methods that operate on files, directories, or other types of files.
Files
类包含专门用于操作文件、目录或其他类型文件的静态方法。这些方法使普通文件操作变得简单。9.1 读写文件
static byte[] readAllBytes(Path path); static List<String> readAllLines(Path path); static Path write(Path path, byte[] bytes, OpenOption... options); static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options); static Path write(Path path, Iterable<? extends CharSequence> lines, OpenOption... options);
实现
OpenOption
接口的StandardOpenOption
:StandardOpenOption枚举常量解释Files
类提供的文件读写方法适合中等长度的文本文件,如果是大型文件,或者是二进制文件,还是应该使用流或者读入/读出器static InputStream newInputStream(Path path, OpenOption... options) //Opens a file, returning an input stream to read from the file. static OutputStream newOutputStream(Path path, OpenOption... options) //Opens or creates a file, returning an output stream that may be used to write bytes to the file. static BufferedReader newBufferedReader(Path path) //Opens a file for reading, returning a BufferedReader to read text from the file in an efficient manner. static BufferedReader newBufferedReader(Path path, Charset cs) //Opens a file for reading, returning a BufferedReader that may be used to read text from the file in an efficient manner. static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... options) //Opens or creates a file for writing, returning a BufferedWriter that may be used to write text to the file in an efficient manner. static BufferedWriter newBufferedWriter(Path path, OpenOption... options) //Opens or creates a file for writing, returning a BufferedWriter to write text to the file in an efficient manner.
9.2 复制、移动、删除文件
static long copy(InputStream in, Path target, CopyOption... options) //Copies all bytes from an input stream to a file. static long copy(Path source, OutputStream out) //Copies all bytes from a file to an output stream. static Path copy(Path source, Path target, CopyOption... options) //Copy a file to a target file. static Path move(Path source, Path target, CopyOption... options) //Move or rename a file to a target file. static void delete(Path path) //Deletes a file. static boolean deleteIfExists(Path path) //Deletes a file if it exists.
实现
CopyOption
接口的StandardCopyOption
:StandardCopyOption枚举常量解释9.3 创建文件和目录
static Path createDirectories(Path dir, FileAttribute<?>... attrs) //Creates a directory by creating all nonexistent parent directories first. static Path createDirectory(Path dir, FileAttribute<?>... attrs) //Creates a new directory. static Path createFile(Path path, FileAttribute<?>... attrs) //Creates a new and empty file, failing if the file already exists. static Path createLink(Path link, Path existing) //硬链接 //Creates a new link (directory entry) for an existing file (optional operation). static Path createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)//符号链接 //Creates a symbolic link to a target (optional operation). static Path createTempDirectory(Path dir, String prefix, FileAttribute<?>... attrs) //Creates a new directory in the specified directory, using the given prefix to generate its name. static Path createTempDirectory(String prefix, FileAttribute<?>... attrs) //Creates a new directory in the default temporary-file directory, using the given prefix to generate its name. static Path createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs) //Creates a new empty file in the specified directory, using the given prefix and suffix strings to generate its name. static Path createTempFile(String prefix, String suffix, FileAttribute<?>... attrs) //Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name.
9.4 获取文件信息
static boolean exists(Path path, LinkOption... options) //Tests whether a file exists. static boolean isDirectory(Path path, LinkOption... options) //Tests whether a file is a directory. static boolean isExecutable(Path path) //Tests whether a file is executable. static boolean isHidden(Path path) //Tells whether or not a file is considered hidden. static boolean isReadable(Path path) //Tests whether a file is readable. static boolean isRegularFile(Path path, LinkOption... options) //Tests whether a file is a regular file with opaque content. static boolean isSameFile(Path path, Path path2) //Tests if two paths locate the same file. static boolean isSymbolicLink(Path path) //Tests whether a file is a symbolic link. static boolean isWritable(Path path) //Tests whether a file is writable. static <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options) //Reads a file's attributes as a bulk operation. static Map<String,Object> readAttributes(Path path, String attributes, LinkOption... options) //Reads a set of file attributes as a bulk operation. static long size(Path path) //Returns the size of a file (in bytes).
BasicFileAttributes
接口:BasicFileAttributesLinkOption
:
LinkOption枚举常量解释9.5 迭代目录中的文件
如果要获取一个目录中所有文件:
static DirectoryStream<Path> newDirectoryStream(Path dir) //Opens a directory, returning a DirectoryStream to iterate over all entries in the directory. static DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) //Opens a directory, returning a DirectoryStream to iterate over the entries in the directory. static DirectoryStream<Path> newDirectoryStream(Path dir, String glob) //Opens a directory, returning a DirectoryStream to iterate over the entries in the directory.
如果想要访问某个目录的所有子孙成员:
tatic Path walkFileTree(Path start, FileVisitor<? super Path> visitor) //Walks a file tree. static Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor) //Walks a file tree.
FileVisitor接口定义的方法: