IO
输入和输出
Java API
中,可从中读入一个字节序列的对象叫输入流,可以写入一个直接对象成为输出流;
抽象类InputStream
和OutputStream
是I/O
包的基础。
因为面向字节的流不便于处理Unicode
编码信息,抽象出来Reader
和Writer
专门处理,衍生类的读去和写入操作都是基于两个字节的Char
值的。
InputStream
操作 | 内容 |
---|---|
int read() throws IOException; | 读取并返回一个字节,结束返回-1 |
int available() throws IOException; | 返回可读入的字节数量 |
read
其他方法都基于read()
实现
OutputStream
操作 | 内容 |
---|---|
int write(int b) throws IOException; | 写入一个字节 |
write
其他方法都基于write(int b)
实现
阻塞
read
和write
在执行时都将阻塞,直到字节确实被读入或写出。这意味着等待过程=线程阻塞。当完成操作后,应当调用close
关闭I/O
流。 对于任何Closeable
接口可以使用try-with-resouce
进行自动关闭操作.
结合 输入/输出流
文件流File{Input|Output}Stream
提供了对磁盘文件的文件流。
java.io 中的类相对路径的解释以用户工作目录开始,通过
System.getProperty("user.dir")
查看
Java
中的流可以嵌套使用,即继承之FilterInputStream/FilterOutputStream
的类可用于向处理字节的流添加额外的功能。
public static void main(String[] args) throws IOException {
Path p = Paths.get(System.getProperty("user.dir"), "resources", "1.txt");
InputStream inputStream = new FileInputStream(p.toFile());
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
}
文本流
Java
内部使用UTF-16
编码,即一个字符使用16位(2个字节)保存,字符串“1234”编码为(0031 0032 0033 0034).
OutputStreamWriter
将输出流转换为字节流,InputStreamReader
将字节流转换位Java
可以理解的字符。
例如 从键盘获取一行输入
public static void main(String[] args) throws IOException {
try (
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
) {
String s = in.readLine();
System.out.println(s);
}
}
写文本
文本输出,可使用PrintWriter
对象,使用print
,println
和printf
方法输出。
try (PrintWriter out = new PrintWriter("1.txt", StandardCharsets.UTF_8.toString());) {
out.println("hello world");
}
读文本
使用Scanner
读取文本输入,可以从InputStream
构建,
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
}
早期Java
版本,只能通过BufferedReader
的readLine
获取下一行文本。
BufferedReader
加入了一个lines
方法,可以产生一个Stream<String>
数组.
Scanner
可以读取非字符串类型,而BufferedReader
当前版本不可以。
文件API
Path
获取
Path
表示一个路径,
通过静态方法Paths.get(String first, String... more)
获取路径
路径不必对于某个实际存在的文件,它只是一个抽象的名称序列.
相对路解析
获取Path
对象后,可调用resolve
获得相对路径. resolveSibling
得到同级兄弟目录
resolve
的反向操作时relative
例如在/home/fred/myprog
对/home/cay
调用relative
会产生../fred/myprog
normalize
删除冗余的.
和..
toAbsoultPath
产生绝对路径
getRoot
根路径 /
D:\
getFileName
文件(夹)名 getParent()
父路径 toFile
获得File
对象
通过File
对象的toPath
可以获得Path
对象
Files
读写文件
Files.readAllBytes
读取一个文件的所有字节内容 List<String> readAllLines
获得所有行 newInputStream/newOutputStream/newBufferedReader/newBufferedWriter
从路径获得指定流 Files.write
向指定路径写入字节
文件/目录创建
createDirectory
创建单个目录(要求目录前置目录以存在) createDirectories
创建目录(自动创建中间目录) createFile
创建文件(如果文件已存在,调用抛出异常, 检测和创建时原子操作) 临时文件创建 createTempDirectory/createTempFile
复制/移动/删除
File.copy
复制 File.move
移动 (覆盖使用 REPLACE_EXISTING, 复制文件属性 使用COPY_ATTRIBUTES)
Files.copy(f, f.resolveSibling("test.txt.cpy"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
File.delete(path)
删除(如果文件不存在,会抛出异常) File.deleteIfExists
如果存在才删除
获取文件信息
检测文件属性
exists
存在 notExists
不存在 isReadable
isWritable
isExecutable
isSymbolicLink
链接文件 isDirectory
isRegularFile
常规文件
size
文件字节数 getOwner
文件所有者
readAttributes
读取封装信息 例如获取基础属性
BasicFileAttributes attributes = Files.readAttributes(f, BasicFileAttributes.class);
System.out.println(attributes);
BasicFileAttributes
封装了lastModifiedTime
等信息
目录检索
Stream<Path>list(Path dir)
返回一个路径流,目录读取是惰性的 list
不会进入子目录 Stream<Path> walk
可对目录中所有子目录进行检索(深度优先),可以指定深度。
目录流
newDirectoryStream
可以产生一个目录流,它是专门用于遍历目录的接口,可以使用增强for循环.
public interface DirectoryStream<T>
extends Closeable, Iterable<T>
这个方法可以使用glob
来过滤文件,例如只要java
结尾的文件
细粒度的控制
使用walkFileTree
,传入一个FileVisitor
FileVisitor
preVisitDirectory 访问目录前
visitFile 访问文件
visitFileFailed 访问文件失败
postVisitDirectory 访问文件夹后
方法返回FileVisitResult
枚举