I/O 流

1 可以从其中读入一个字节序列的对象称做输入流,而可以向其中写入一个字节序列的对象称做输出流。这些字节序列的来源地和目的地可以是文件,而且通常都是文件,但是也可以是网络连接,甚至是内存块
2 抽象类InputStream和OutputStream构成了输入/输出(I/O)类层次结构的基础。
3 从抽象类Reader和Writer中继承出来了一个专门用于处理Unicode字符的单独的类层次结构,属于字符流 而非 字节流
4 inputStream 有个 抽象的read方法 用于去读字节 或者读取字节数组,返回读取的字节 或者 遇到EOF 返回-1
5 OutputStream 有个抽象的 write 方法 用于写入字节
6 read 和 write 都是阻塞的
7 当你完成对输入/输出流的读写时,应该通过调用close方法来关闭它,可以释放系统资源,并且会刷新缓冲区
8 InputStream和OutputStream类可以读写单个字节或字节数组,但很少直接使用字节流,更感兴趣的是对象 字符串等
image.png
image.png
9 对于Unicode文本,可以使用抽象类Reader和Writer的子类,read方法将返回一个Unicode码元,write写入一个Unicode字符
image.png
10 FileInputStream和FileOutputStream可以提供附着在一个磁盘文件上的输入流和输出流,而你只需向其构造器提供文件名或文件的完整路径名
11 某些输入流(例如FileInputStream)可以从文件上获取字节,而其他的输入流(如DataInputStream)可以将字节组装到更有用的数据类型中,Java程序员必须对二者进行组合
12 你可以通过嵌套过滤器来添加多重功能,如输入流默认不缓存,中间加一个BufferedInputStream就可以实现缓存功能
13 pushBackInputStream 可以读完之后 再退回 输入流中
14 ZipInputStream 可以从压缩文件中读取数据 new DataInuptStream(new ZipInputStream(new FileInputStream))

文本格式输入输出

1 在保存数据时,可以选择二进制格式或文本格式 ,前者效率高 后者易于阅读
2 在存储文本字符串时,需要考虑字符编码,Java内部使用 utf-16 编码(十六进制)
3 OutputStreamWriter类将使用选定的字符编码方式,把Unicode码元的输出流转换为字节流
4 InputStreamReader类将包含字节(用某种字符编码方式表示的字符)的输入流转换为可以产生Unicode码元的读入器,可以手动选择一种编码方式
5 通过PrintWriter实现文本输出,通过调用print println printf 来打印,println会冲刷缓冲区,其完整含义类似于 new PrintWriter(new FileOutputStream(“..”,..))
6 通过Scanner类 可以读取文本,可以从任何输入流中 构建 Scanner
或者调用Files的静态 readAllBytes readAllline 将文本读入一个字符串, 或者一个字符流
或者用BufferReader , 但这个不能读取数字

读写二进制数据

1 读写二进制数据的效率更高
2 DataInputStream类实现了DataInput接口,为了从文件中读入二进制数据,可以将DataInputStream与某个字节源相组合,例如FileInputStream
3 DataOutputStream 实现了DataOutput 用于写入二进制数据,可以与FileOutputStream 组合
4 RandomAccessFile类可以在文件中的任何位置查找或写入数据。磁盘文件都是随机访问的
5 seek方法可以用来将这个文件指针设置到文件中的任意字节位置,seek的参数是一个long类型的整数,它的值位于0到文件按照字节来度量的长度之间,getFilePointer方法将返回文件指针的当前位置。
6 RandomAccessFile类是实现了 DataInput和DataOutput接口, 可以调用方法用来读写二进制文件

对象输入输出/序列号

1 保存对象 需要 先打开ObjectOutputStream,调用writeObject 对象
new ObjectOutputStream(new FileInputStream(“xxxx”));
2 读取对象 需要 调用 readObject ,按写出的顺序读取的
Empolyee e = (Eployeee)in.readObject();
3 保存和写入的类 必要要 实现 Serializable 接口,Serializable接口没有任何方法,因此你不需要对这些类做任何改动

操作文件

1 Path类 和 Files 可以用于管理文件
2 Path表示的是一个目录名序列,其后还可以跟着一个文件名, 可以是相对路径,也可以是绝对路径
3 通过Paths.get(“”) 可以从字符串中创建,可以接受多个字符串 然后以 系统的分隔符 合并
4 Files 可以将文本文件读入字节数组 通过静态的 readAllBytes 函数 ,再通过String的构造函数 选择编码方式 构建字符串
5 还可以调用Files.write 函数向文件写入一个字符串
Files.write(path,content.getBytes(charset));
6 Files类的读写适用于中等长度的文本,对于大文件 还是用输入输出流更合适
7 Files.createDirectory(path), createDirectories(path) 用于创建目录,后面复数形式的函数可以创建中间不存在的目录
8 Files.createFile(path) 用于创建文件,如果文件已经存在了,那么这个调用就会抛出异常
9 Files.copy 用于复制文件 Files.move 移动文件 如果目标已存在 可以加额外的参数 Files.delete用于删除文件 不存在会抛出异常 最好用 Files.deleteIfExists(path)
10 Files.size() Files.exits() Files.isHidden() Files.isReadable() Files.isDirectory() 等方法 可以获取文件的信息
所有的文件系统都会报告一个基本属性集,它们被封装在BasicFileAttributes接口
11 Files.list 方法返回目录中的项,返回 Stream, 是惰性读取的 效率高

内存映射文件

1 内存映射比使用带缓冲的顺序输入要稍微快一点
2 对于中等尺寸文件的顺序读入则没有必要使用内存映射
3 使用内存映射文件首先从文件中获得一个通道(channel),然后通过map方法获得ByteBuffer,映射模式是可选的, 只读 修改共享 修改私有三个模式

  1. FileChannel channel = FileChannel.open(path,options);
  2. ByteBuffer b = channel.map(mode,position,size);

4 接下来就可以使用ByteBuffer类和Buffer超类的方法读写数据了
5 除了文件以外,还可以使用更多的缓冲区来读写大小适度的信息块
6 Buffer类是一个抽象类,它有众多的具体子类,包括ByteBuffer、CharBuffer、DoubleBuffer、IntBuffer、LongBuffer和ShortBuffer
7 Buffer具有固定的容量,具有一个读写位置,具有一个界限,以及一个可选的标记(是否重复读入),0≤标记≤位置≤界限≤容量
8 多个程序可能同时修改文件,所以文件锁 也很有必要,可以控制对文件或文件中某个范围的字节的访问
9 通过调用FileChannel.lock tryLock 等方法实现 文件的加锁
10 可以锁定文件的一部分, lock(start,size,shared) shared表示共享锁,可以允许多个进程读
11 最好用try语句实现 释放锁 try(FileLock lock = channel.lock())
12 文件锁高度依赖于操作系统 需要谨慎使用

正则表达式

1 正则表达式用于指定字符串的模式
2 正则表达式的最简单用法就是测试某个特定的字符串是否与它匹配