Java IO流学习总结

1. 输入与输出流

  • 输入流
    可以从其中读入一个字节序列的对象
  • 输出流
    可以从其中写入一个字节序列的对象

1.1 读写字节

  1. InputStream类有一个抽象方法,用于读入一个直接,并返回读入的直接,当遇到结尾时返回-1
abstract int read()
  1. 类似的,OutputStream类定义了一个方法,用于向某个输出位置写出一个字节
abstract void write()
  1. readwrite方法在执行时都将被阻塞,直至直接确实被读入或写出。这就意味着如果留不能被立即访问,那么当前线程将被阻塞,这个时候,其他线程就有机会去执行更有用的工作
  2. available方法用于检查当前可读入的字节数量
  3. close方法用于当你完成输入/输出流的读写时,你可以通过此方法去关闭它。
  4. flush方法可以人为的对输出流进行冲刷

1.2 完整的流家族

Java的流家族非常强大,包含各种输入/输出流类型,数量超过60个!

InputStream和OutputStream

如果把输入/输出流成员按使用方法来分,这样就形成了处理字节字符两个单独的层次结构。
- InputStreamOutputStream用于读写单个字节或字节数组
- DataInputStreamDataOutputStream以二进制格式读写所有的基本Java类型
- ZipInputStreamZipOutputStream可以以ZIP压缩格式读写文件

如果想要读取其他东西例如字符串数字,就需要功能更强大的子类。

Reader和Writer

对于Unicode文本,也是使用抽象类ReaderWriter的子类
ReaderWriter的基本方法与InputStreamOutputStream类似

abstract int read()
abstract void write(int c)
  • read方法将返回一个Unicode码元(一个在0~65535之间的整数),或者在碰到文件结尾时返回-1
  • write方法在调用时,需要传入一个Unicode码元

4个附加接口

4个附加接口CloseableFlushableReadableAppendable

  1. Closeable
    这个接口实现了void close() throws IOException方法
    InputStreamOutputStreamReaderWriter都实现了此接口
  2. Flushable
    这个接口实现了void flush()方法
    OutputStreamWriter都实现了此接口
  3. Readable
    这个接口实现了int read(CharBuffer cb)方法
    CharBuffer类拥有按顺序和随机地进行读写访问的方法,他表示一个内存中的缓冲区或者一个内存映像的文件
  4. Appendable
    此接口有两个方法Appendable append(char c)Appendable append(CharSequence s)
    CharSequence接口描述了一个char值序列的基本属性,在流类家族中,只有Writer实现了他

1.3 组合输入/输出过滤器

FileInputStreamFileOutputStream可以提供附着在一个磁盘文件上的输入流和输出流,你只需要提供文件名或者文件的完整路径

FileInputStream fin  new FileInputStream("1.txt");

但是他们和InputStreamOutputStream一样,只支持读写字节,所以万一你想从一个文件中读取或者写入一个数字,光靠这几个是不行的
相信你一定知道,DataInputStream可以用来读入数值,这个时候你就可以对其进行组合
首先你得先创建一个FileInputStream对象,然后将其传输给DataInputStream

FileInputStream fin = new FileInputStream("1.txt");
DataInputStream din = new DataInputStream(fin);

你也可以使用嵌套的方法创建这个DataInputStream对象

DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream("1.txt")));

2. 文本输入与输出

在保存数据时,可以选择二进制格式或文本格式
* InputStreamReader
把输入==字节==流转为==字符==流
* OutputStreamWriter
把输出==字符==流转为==字节==流

2.1 如何写出文本输出

对于文本输出可以使用PrintWriter
这个类有很多以文本格式打印字符串和数字的方法

void print(boolean b) //打印布尔值
void print(char c) //打印一个字符
void print(char[] s) //打印字符数组
void print(double d) //打印双精度浮点数
void print(float f) //打印浮点数
void print(int i) //打印一个整数
void print(long l) //打印一个长整数
void print(Object obj) //打印一个对象
void print(String s) //打印字符串
PrintWriter printf(Locale l, String format, Object... args)
//使用指定的格式字符串和参数将格式化的字符串写入该writer的方便方法
PrintWriter printf(String format, Object... args) //使用指定的格式字符串和参数将格式化的字符串写入该writer的方便方法
void println() //通过写入行分隔符字符串来终止当前行
void println(boolean x) //打印一个布尔值,然后终止该行
void println(char x) //打印一个字符,然后终止该行
void println(char[] x) //打印字符数组,然后终止行
void println(double x) //打印双精度浮点数,然后终止行
void println(float x) //打印一个浮点数,然后终止该行
void println(int x) //打印一个整数,然后终止该行
void println(long x) //打印一个长整型,然后终止行
void println(Object x) //打印一个对象,然后终止该行
void println(String x) //打印一个字符串,然后终止行

他将把字符输出到写出器out,然后这些字符将会转为字节并写入文件中

2.2 字符编码方式

输入和输出流都是用于字节序列
- StandardCharsets类具有类型为Charset的静态变量,用于表示每种Java虚拟机都必须支持的字符编码方式

StandardCharsets.UTF_8
StandardCharsets.UTF_16
StandardCharsets.UTF_16BE
StandardCharsets.UTF_16LE
StandardCharsets.ISO_8859_1
StandardCharsets.US_ASCII
  • 为了获得另一种编码方式的Charset,可以使用静态的forName方法
Charset shiftJIS = Charset.forName("Shift-JIS");
  • 在读入或写出文本时,应该使用Charset对象

3. 读写二进制数据

文本格式虽说易于人们阅读,但是很多地方,他并不像二进制格式那么高效

3.1 DataInput和DataOutput

  • DataOutput接口定义了下面用于以二进制格式数组、字符、boolean值和字符串的方法
void write(byte[] b) //将输出流写入数组 b中的所有字节
void write(byte[] b, int off, int len) //从阵列 b写入 len字节,以输出流
void write(int b) //向输出流写入参数 b的八个低位
void writeBoolean(boolean v) //将 boolean值写入此输出流
void writeByte(int v) //向输出流写入参数 v的八个低位位
void writeBytes(String s) //将一个字符串写入输出流
void writeChar(int v) //将两个字节组成的 char值写入输出流
void writeChars(String s) //写入每一个字符在字符串中 s ,到输出流中,为了,每个字符使用两个字节
void writeDouble(double v) //将 double值(由8个字节组成)写入输出流
void writeFloat(float v) //将 float值写入输出流,该值由四个字节组成
void writeInt(int v) //将 int值(由四个字节组成)写入输出流
void writeLong(long v) //将 long值(由八个字节组成)写入输出流
void writeShort(int v) //将两个字节写入输出流以表示参数的值
void writeUTF(String s) //将两个字节的长度信息写入输出流,其后是 字符串 s中每个字符的s
  • DataOutput接口定义了下面用于以二进制格式数组、字符、boolean值和字符串的方法
boolean readBoolean() //读取一个输入字节,并返回 true如果该字节不为零, false如果该字节是零
byte readByte() //读取并返回一个输入字节
char readChar() //读取两个输入字节并返回一个 char值
double readDouble() //读取八个输入字节并返回一个 double值
float readFloat() //读取四个输入字节并返回一个 float值
void readFully(byte[] b) //从输入流读取一些字节,并将它们存储到缓冲区数组 b 
void readFully(byte[] b, int off, int len) //从输入流读取 len个字节
int readInt() //读取四个输入字节并返回一个 int值
String readLine() //从输入流读取下一行文本
long readLong() //读取八个输入字节并返回一个 long值
short readShort() //读取两个输入字节并返回一个 short值
int readUnsignedByte() //读取一个输入字节,将其扩展到类型 int ,并返回结果,因此在 0到 255
int readUnsignedShort() //读取两个输入字节,并返回 0到 65535的 int值
String readUTF() //读取已使用 modified UTF-8格式编码的字符串
int skipBytes(int n) //尝试从输入流中跳过 n字节的数据,丢弃跳过的字节

3.2 随机访问文件

RandomAccessFile类可以访问文件中的任意位置。很多资料把它翻译成随机访问文件,但是个人觉得应该翻译为任意访问文件,他是能访问文件中的任意位置。
- 你可以打开一个文件,只用于读入或者同时写入,只需要在构造器加上”r”(用于读入访问),”rw”(用于读入/写出访问)

RandomAccessFile in = new RandomAccessFile("employee.dat", "r");
RandomAccessFile inOut = new RandomAccessFile("employee.dat", "rw");
  • 方法
void close() //关闭此随机访问文件流并释放与流相关联的任何系统资源。  
FileChannel getChannel() //返回与此文件关联的唯一的FileChannel对象。  
FileDescriptor getFD() //返回与此流关联的不透明文件描述符对象。  
long getFilePointer() //返回此文件中的当前偏移量。  
long length() //返回此文件的长度。  
int read() //从该文件读取一个字节的数据。  
int read(byte[] b) //从该文件读取最多 b.length字节的数据到字节数组。  
int read(byte[] b, int off, int len) //从该文件读取最多 len个字节的数据到字节数组。  
boolean readBoolean() //从此文件读取一个 boolean 。  
byte readByte() //从此文件中读取一个带符号的八位值。  
char readChar() //从此文件中读取一个字符。  
double readDouble() //从此文件读取 double 。  
float readFloat() //从此文件读取一个 float 。  
void readFully(byte[] b) //从此文件读取 b.length字节到字节数组,从当前文件指针开始。  
void readFully(byte[] b, int off, int len) //从此文件中读取 len个字节到字节数组,从当前文件指针开始。  
int readInt() //从该文件读取一个带符号的32位整数。  
String readLine() //从此文件中读取下一行文本。  
long readLong() //从该文件中读取一个带符号的64位整数。  
short readShort() //从此文件中读取一个已签名的16位数字。  
int readUnsignedByte() //从此文件中读取一个无符号的八位数字。  
int readUnsignedShort() //从该文件中读取一个无符号的16位数字。  
String readUTF() //从该文件读取字符串。  
void seek(long pos) //设置文件指针偏移,从该文件的开头测量,发生下一次读取或写入。  
void setLength(long newLength) //设置此文件的长度。  
int skipBytes(int n) //尝试跳过 n字节的输入丢弃跳过的字节。  
void write(byte[] b) //从指定的字节数组写入 b.length个字节到该文件,从当前文件指针开始。  
void write(byte[] b, int off, int len) //从指定的字节数组写入 len个字节,从偏移量 off开始写入此文件。  
void write(int b) //将指定的字节写入此文件。  
void writeBoolean(boolean v) //将 boolean写入文件作为一个字节值。  
void writeByte(int v) //将 byte写入文件作为单字节值。  
void writeBytes(String s) //将字符串作为字节序列写入文件。  
void writeChar(int v) //将 char写入文件作为两字节值,高字节为先。  
void writeChars(String s) //将一个字符串作为字符序列写入文件。  
void writeDouble(double v) //双参数传递给转换 long使用 doubleToLongBits方法在类 Double ,然后写入该 long值到该文件作为一个八字节的数量,高字节。  
void writeFloat(float v) //浮子参数的转换 int使用 floatToIntBits方法在类 Float ,然后写入该 int值到该文件作为一个四字节数量,高字节。  
void writeInt(int v) //将 int写入文件为四个字节,高字节 int 。  
void writeLong(long v) //将 long写入文件为八个字节,高字节为先。  
void writeShort(int v) //将 short写入文件作为两个字节,高字节优先。  
void writeUTF(String str) //以机器无关的方式使用 modified UTF-8编码将字符串写入文件。 

3.3 ZIP压缩文件

ZIP通常是压缩文件包的格式,他能对一个或者一群文件进行压缩整合到一个.zip压缩包中。
在java中,使用输入/输出流可以快速的读入或者输出zip文件
* ZipInputStream
ZipInputStream可以用来读入一个zip文件,使用ZipNextEntry方法就可以返回一个描述这些项的ZipEntry对象。getInputStream可以用来返回一个InputStream输入流

ZipInputStream zin = new ZipInputStream(new FileInputStream(Zipname));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null{
    InputStream in = zin.getInputStream(entry);
    // read the contents of in
    zin.closeEntry();
}
zin.close();
  • ZipOutputStream
    ZipOutputStream可以用来输出一个zip文件,对于你想放到压缩包中的每一项,你都得建一个ZipEntry对象,并将文件名传给ZipEntry的构造器。
FileOutputStream fout = new FileOutputStream("test.zip");
ZipOutputStream zout = new ZipOutputStream(fout);
// for all files
{
    ZipEntry ze = new ZipEntry(filename);
    zout.putNextEntry(ze);
    // send data to zout
    zout.cliseEntry();
}
zout.close();

4. 对象输入/输出流与序列化

Java语言支持一种称为对象序列化的非常通用的机制,它可以将任何对象写出到输出流,并在之后将其读回

4.1 保存和加载序列化对象

1. 输出

  • 首先打开一个ObjectOutputStream对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.dat"));
  • 然后使用writeObject方法
Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);
Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
out.writeObject(harry);
out.writeObject(boss);

2. 读入

  • 首先获得一个ObjectInoutStream对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("employee.dat"));
  • 用readObject方法
Employee e1 = (Employee) in.readObject();
Employee e2 = (Employee) in.readObject();

3. 前提

如果想要使用对象的输入输出,就得让类实现Serializable接口。
Serializable接口没有任何方法,因此不需要做啥更改,只需要extends Serializable就行了

5. 操作文件

PathFiles类封装了在用户机器上处理文件系统所需的所有功能。但是比前面对输入输出流操作方便得多。
他们两个都是Java SE 7新添加进来了。

5.1 Path

Path表示的是一个目录名序列,其后还可以跟着一个文件名。路径中第一个参数可以是根目录。
- Paths.get

public static Path get(String first, String... more)

这个方法接收一个或多个字符串。如果只接受一个字符串,那么first参数的值是要转换的路径字符串。如果指定了多个字符串,则每个非空字符串被认为是名称元素的序列,并且被连接以形成路径字符串。
- resolve
调用p.resolve(q)将按照下列规则返回一个路径
- 如果q是绝对路径,这结果就是q
- 否则,根据文件系统的规则,将p后面跟着q作为结果

Path workRelative = Paths.get("work");
Path workPath = basePath.resolve(workRelative);
  • getName
Path getName(int index)

返回此路径的名称元素作为Path对象。index参数是要返回的名称元素的索引。目录层次结构中最靠近根的元素索引为0 。离根最远的元素索引为count -1
- isAbsolute

boolean isAbsolute()

判断这条路径是否是绝对路径

5.2 读写文件

Files类可以使得普通文件操作便得简单效率而且便捷。
- readAllBytes

public static byte[] readAllBytes(Path path) throws IOException

读取文件中的所有字节
- readAllLines

public static List<String> readAllLines(Path path) throws IOException

从文件中读取所有行
- write

public static Path write(Path path,
                         Iterable<? extends CharSequence> lines,
                         Charset cs,
                         OpenOption... options)
                  throws IOException

向指定文件追加内容

如果要处理的文件长度比较长,或者是二进制文件,那么还是应该使用所熟知的输入/输出流或者读入器/写出器

5.3 创建文件和目录

  • createDirectory
public static Path createDirectory(Path dir,
                                   FileAttribute<?>... attrs)
                            throws IOException

创建一个新的目录,除了最后一个要被创建的目录外,其他中间目录必须存在。
- createDirectories

public static Path createDirectories(Path dir,
                                     FileAttribute<?>... attrs)
                              throws IOException

创建最终目录的同时创建中间目录
- createFile

public static Path createFile(Path path,
                              FileAttribute<?>... attrs)
                       throws IOException

创建一个新的和空的文件,如果该文件已存在,则抛出异常
- createTemp

createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs)//在指定的目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称
createTempFile(String prefix, String suffix, FileAttribute<?>... attrs)//在默认临时文件目录中创建一个空文件,使用给定的前缀和后缀生成其名称
createTempDirectory(Path dir, String prefix, FileAttribute<?>... attrs)//在指定的目录中创建一个新目录,使用给定的前缀生成其名称
createTempDirectory(String prefix, FileAttribute<?>... attrs)//在默认临时文件目录中创建一个新目录,使用给定的前缀生成其名称

5.4 复制、移动和删除

  • copy
Files.copy(fromPath, toPath);

将文件从一个位置复制到另一个位置
- move

Files.move(fromPath, toPath);

移动文件
- delete

Files.delete(path);

删除文件,如果文件不存在,则会抛出异常
- deleteIfExists

Files.deleteIfExists(path)

删除文件(如果存在)。如果文件是目录,那么该目录必须为空。

5.5 访问目录中的项

  • Files.list
    返回一个可以读取目录中各个项的Stream对象,但是这个方法不会进入子目录
try (Stream<Path> entries = Files.list(pathToDirectory))
{
    ...
}
  • Files.walk
    返回一个可以读取目录中各个项的Stream对象,这个方法进入子目录
try (Stream<Path> entries = Files.walk(pathToDirectory))
{
    // Contains all descendants, visited in depth-first order
}

6. 内存映射文件

6.1 内存映射文件的性能

  • 构造器
    从文件中获得一个通道
FileChannel channle = FileChannel.open(path, options);
  • map
    map方法可以从这个通道中获得一个ByteBuffer,你得选择映射的模式
    • FileChannel.MapMode.READ_ONLY 只读
    • FileChannel.MapMode.READ_WRITE 可写,任何修改都会在某个时刻写回到文件中
    • FileChannel.MapMode.PRIVATE 缓冲区是可写的,但是任何修改对这个缓冲区来说都是私有的,不会传播到文件中
MappedByteBuffer inBuf = fcIn.map(FileChannel.MapMode.READ_ONLY, 0, size);

6.2 缓冲区数据结构

缓冲区是由具有相同类型的数值构成的数组,Buffer是一个抽象类,他有众多的子类,包括ByteBuffer,CharBuffer,DoubleBuffer、IntBuffer、LongBuffer和ShortBuffer。

StringBuffer与这些没关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值