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不存在 isReadableisWritableisExecutableisSymbolicLink 链接文件 isDirectoryisRegularFile 常规文件
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枚举
