Java.io
Java中可以从其中读入一个字节序列的对象称作为输入流。可以向其中写入一个字节序列的对象称为输出流。这些字节序列的来源可以是文件,也可以是网络连接和内存。输入/输出流家族家中类的数量超过了60个,下面列举了常用的类。
字节流
InputStream与OutputStream是java.io包提供的抽象类,定义了读写字节流的抽象方法,真正的读写方法由子类实现。读写方法read和write方法在执行时都将阻塞,直到字节确实被读入或者写出。这使得工作线程在等待流变得可用这段时间里,其他的线程有机会执行有用的工作。
在完成对输入、输出流的的读写后,应该调用close方法来关它,来释放操作系统掉操作系统十分有限的资源(在linux中可以使用ulimit来设置)。在关闭一个输出流的同时还会刷新用于该输出流的缓冲区,当然也可以使用flush来刷新它。
java.io.InputStream
- abstract int read(), 从数据中读入一个字节,并返回该字节。碰到输入流的结尾时返回-1
- int read(byte[] b) 读入数据到字节数组,并返回实际读入的字节数,碰到输入流的结尾时返回-1
- int read(byte[] b, int off, int len), 读入数据到字节数组,并且指定偏移量和最大填充数,碰到输入流的结尾时返回-1,
- long skip(long n ), 在输入流中跳过n个字节,并返回实际跳过的字节数
- int available(), 返回在不阻塞的情况下可获取的字节数
- void close() 关闭这个输入流
java.io.OutputStream
- abstract void write(), 写出一个字节的数据
- void write(byte[] b)
- void write(byte[] b, int offm int len),将字节数组b中的第off+1个元素开始的len个数据。顺序的写入此输出流中
- void close() 冲刷并关闭输出流
void flush() 冲刷输出流,也就是将所有缓冲的数据发送到目的地。
文件读写
java.io.FileInputStream
FileInputStream(String name) 使用文件地址来创建一个新的文件输入流
- FileInputStream(FIle file) 使用file对象指定的路径名来创建一个新的文件输入流
java.io.FileOutputStream
- FileOutputStream(String name)
- FileOutputStream(String name, boolean append)
- FileOutputStream(FIle file)
- FileOutputStream(File file, boolean append) ```java package com.example.demo;
import java.io.*;
public class FileStreamTest {
public static void processFile(String pathName) throws IOException {
File file = new File(pathName);
try (OutputStream output = new FileOutputStream(file)) {
byte data[] = {1, 2, 3, 4, 5};
output.write(data);
}
try (InputStream input = new FileInputStream(file)) {
int n;
while ((n = input.read()) != -1) {
System.out.println(n);
}
}
}
public static void main(String[] args) {
try {
processFile("C:\\Users\\Desktop\\data.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
<a name="qZg6O"></a>
### 字节数组读写
**java.io.ByteArrayInputStream**
- ByteArrayInputStream(bye[] buf)使用内存中的数组来创建一个输入流
**java.io.ByteArrayOutputStream**
- ByteArrayInputStream(bye[] buf)使用内存中的数组来创建一个输出流
<a name="O6D5I"></a>
### 对象的序列化
java.io包提供了将java对象序列化与反序列的接口。前提是该类必须实现了serializable接口,而且反序列化时JVM中存在该类的class对象。<br />[**serialVersionUID**](https://www.cnblogs.com/qq3111901846/p/7894532.html)<br />serialVersionUID用于校验序列化的版本一致性,如果不手动指定,据编译的Class自动生成一个。序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断根据该字段来判断版本是否正确
```java
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
private String sex;
private static final long serialVersionUID = 8735132092273200831L;
// 加上 transient 关键字后Serializable就不会再本地存储该类型
transient private String school;
}
java.io.ObjectInputStream
- ObjectInputStream(InputStream in)
- Object readObject() 从输入流中读入对象
java.io.ObjectOutputStream
- ObjectOutputStream(OutputStream out)
void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
数据管道
管道流一般用于多线程通信,相当于一个基于堆空间内存的消息队列,由锁机制来防止冲突的发生。建议不要尝试使用单个线程中的两个对象,因为可能使线程死锁。
java.io.PipedInputStream
java.io.PipedOutputStream组合输入输出流
输入与输出流可以通过嵌套来实现多种功能,其采用了装饰器设计模式来实现。一般而言DataInputStream就只能从中读取数字,但是没有任何从文件中获取数据的方法,而FileInputStream只能读入文件类型,并从中读入字节或者字节数组;如果我们想从文件中读取数字可以执行一下方法:
FileInputstream fin = new FileInputStream("number.data"); DataInputstream din = new DataInputStream(fin); double x = din.readDouble();
java.io.FilterInputStream/FilterOutputStream
protected FilterInputStream(InputStream in)
protected FilterOutputStream(OutputStream out)
读写二进制数据
文本数据可以方便测试和调试,因为他是人类可以阅读的;但是二进制可以更加高效地传递数据。DataInputStream与DataOutputStream中定义了多种接口用于写二进制数据,例如writeInt总是将一个整数写出为4字节的二进制数值,而不管它有多少位,这样的结果并非是可阅读的,但是对于给定类型的每个值,所产产生的空间都是都是相同的,大大的加快了解析的速度。
DataInputStream in = new DataInputStream(new FileInputStream("test.data")) DataOutputStream out = new dataOutputStream(new FileoutStream("test.data"))
java.io.DataInputStream
int readInt()
- long readLong()
- String readUTF() 读入修订过UTF-8格式字字符构成的字符串
- … …
java.io.DataOutputStream
- void writeByte(itn b)
- void writeChar(int c)
- void writeChars(String s) 写出字符串中所有的字符
String writeUTF() 写出修订过UTF-8格式字字符构成的字符串
缓存流
java.io.BufferedInputStream/BufferedOutputStream
BufferedInputStream(inputStream in) 创建一个带缓冲区的输入流。从流中读入字符时,每次都不会访问设备。当缓冲区为空时,会向缓冲区读入一个新的数据块。
BufferedOutputStream(InputStream in) 创建一个带缓冲区的输出流。带缓冲区的输出流在收集要写出的字符时,每次都不会访问设备。当缓冲区填满或者当流被冲刷时,数据被写出
回退数据
java.io.PushbackInputStream
PushbackInputStream(InputStream in)
- PushbackInputStream(InputStream in, int size),构建一个可以预览一个字节或者具有执行大小的输入流
void unread(int b),回推一个字节,他可以在下次调用read时被再次获取
打印数据
public class PrintStream extends FilterOutputStream implements Appendable, Closeable { /** * The underlying output stream to be filtered. */ protected OutputStream out; private final boolean autoFlush; /** * Track both the text- and character-output streams, so that their buffers * can be flushed without flushing the entire stream. */ private BufferedWriter textOut; private OutputStreamWriter charOut; public void print(char c) { write(String.valueOf(c)); } private void write(String s) { try { synchronized (this) { ensureOpen(); textOut.write(s); textOut.flushBuffer(); charOut.flushBuffer(); if (autoFlush && (s.indexOf('\n') >= 0)) out.flush(); } } catch (InterruptedIOException x) { Thread.currentThread().interrupt(); } catch (IOException x) { trouble = true; } } }
java.io.PrintStream
打印数据,是System.out的实现类其他
java.io.SequenceInputStream
SequenceInputStream(InputStream s1, InputStream s2) 将两个输入流合并成一个输入流
java.io.StringBufferInputStream
- StringBufferInputStream(String s) 将字符串作为输入流
字符流
在保存数据时,可以选择二进制格式或者将二进制数据进行编码的文本格式。Java内部使用是UTF-16作为为默认的编码。字符流中大部分类用法与字节流中的相同,这里不做详细介绍了。
java.io.Reader/Writer
Reader与Writer的基本方法与InputStream和OutputStream类似,区别是Reader与Writer读写的是Unicode码元(一个0-65536之间的则整数)。
字节转换为字符流
java.io.InputStreamReader
- InputStreamReader(InputStream in, String charsetName), 将包含字节的输入流转换为可以产生Unicode码元的读入
java.io.OutputStreamWriter
- OutputStreamReader(putStream out, String charsetName), 使用选定的字符编码方式,把Unicode码元输出流转换为字节流
文件读写
java.io.FileReader ```java import java.io.File; import java.io.FileReader; import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
File f = new File("/root/Test.java");
try (FileReader fr = new FileReader(f)) {
char[] all = new char[(int) f.length()];
fr.read(all);
for (char b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}
try (FileWriter fr = new FileWriter(f)) {
String data="abcdefg1234567890";
char[] cs = data.toCharArray();
fr.write(cs);
} catch (IOException e) {
e.printStackTrace();
}
}
}
**java.io.FileWriter**
```java
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
public static void main(String[] args) {
File f =new File("/root/data.txt");
try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
//强制把缓存中的数据写入硬盘,无论缓存是否已满
pw.println("abc");
pw.flush();
pw.println("123");
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文本输出
对于文本输出可以使用PrintWriter.这个类拥有以文本格式打印字符串和数字得我方法,它还有一个将PrintWriter连接到FileWriter的便捷方法:
PrintWriter out = new PrintWriter("employee.txt", "UTF-8")
java.io.PrintWriter
- PrintWriter(Writer out)
- PrintWriter(OutputStream out)
- PrintWriter(String filename, String encoding)
- PrintWriter(File file, String encoding)
创建一个使用给定编码方式向给定文件写出的新PrintWriter
- void print(Object obj)
- void print(String s)
boolean checkError() 如果格式化或者输出产生错误,将返回true
文本输入
java.util.Scanner
Scanner提供了多种凡是读入文本,不论是字节流还是字符流
文件读入
// 直接将文本读入到字符串中
String content = new String(Files.readAllBytes(path), charset);
// 将文本按行读入到List中
List<String> lines = Files.readAlllines(path, charset);
// 将文本读入到Stream中
try(Stream<String> lines = Files.lines(path, charset))
{
. . .
}
Java.nio
Java NIO全程 java non-blocking IO,是指JDK提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,被统称为NIO,是同步非阻塞的。NIO相比较于BIO有以下区别:
- BIO基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
- BIO是阻塞的,NIO是非阻塞的,Java NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其它的事情。非阻塞也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
- NIO使用了多路复用技术,Selector(选择器)用于监听多个通道的时间(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道。
NIO相关类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写。NIO有三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)。

Selector
Buffer
Buffer类是一个抽象类,是一个由相同类型的数值构成的数组。包括ByteBuffer,CharBuffer等,每一个缓冲区都具有:
- capacity 一个容量,也就是数组的大小,不能够被改变
- position 一个读写位置,下一个值将在此处进行读写
- limit 一个界限,超过它进行读写时没有意义的
mark一个可选的标记,用于重复读入或者写出操作
<br />**java.nio.ByteBuffer**
byte get()从当前位置获得一个字节,并将当前位置移动到下一个字节
ByteBuffer put(byte b) 向当前位置推入一个字节,并将当前位置移动到下一个字节。返回对这个缓冲区的引用
Channel
BIO中的stream是单向的,例如FileInputStream对象只能进行读取数据的操作,而NIO中的通道(Channel)是双向的,可以读操作,也可以写操作常见的Channel类有:FileChannel、DatagramChannel、ServerSocketChannel和SocketChannel。FileChannel用于文件的数据读写,DatagramChannel用于UDP的数据读写,ServerSocketChannel和SocketChannel用于TCP的数据读写
FileChannel
FileChannel是Java.nio提供用于处理文件的类,是一个文件读写、映射和操作的通道,使用它使我们可以访问内存映射,文件加锁以及文件之间数据快速传递等操作系统特性。同时它在并发环境下是线程安全的。
在使用FileChannel时不能直接操作该文件,而是要通过NIO提供的Buffer类。
java.nio.channels.FileChannelstatic FileChannel open(Path path, OpenOption … opentions) 打开指定路径的文件通道,默认用于读入
- options StandardOpenOption 枚举类中WRITE, APPEND, TRUNCATE_EXISTING CREATE
- MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) 将文件的一个区域映射到内存中。
- mode, FileChannel.MapMode类中的常量READ_ONLY,READ_WRITE或者PRIVATE之一
- position 映射区域的起始位置
- size 映射区域的大小
- int read(ByteBuffer dst), 读入数据到指定Buffer中
- int write(ByteBuffer dst), 将指定Buffer中的数据写出到FileChannel中 ```java import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption;
/**
- 测试JAVA NIO方式读取文件,写出内容到文件 / public class NIOTest {
public static void main(String[] args) {
readNIO();
}
/**
* 最终确认,是因为UTF-8编码的时候,是变长的(可能1-4个字节),所以在
* ByteBuffer bf = ByteBuffer.allocate(capacity);
* byte[] bytes = bf.array();
* 的时候,会出现数字英文和中文边界截断了的问题,所以导致出现测���java 文件操作这样的乱码。
* 解决方案1:对这类文件不进行截断输出,整个输出
* 解决方案2:截断输出的时候,判断编码边界。进行减长度操作,避免截断了中文。
*/
public static void readNIO() {
FileInputStream fin = null;
try {
fin = new FileInputStream(new File("D:\\add0.txt"));
FileChannel channel = fin.getChannel();
int capacity = 1024;// 字节
ByteBuffer bf = ByteBuffer.allocate(capacity);
System.out.println("限制是:" + bf.limit() + ",容量是:" + bf.capacity() + " ,位置是:" + bf.position());
int length = -1;
while ((length = channel.read(bf)) != -1) {
/*
* 注意,读取后,将位置置为0,将limit置为容量, 以备下次读入到字节缓冲中,从0开始存储
*/
bf.clear();
byte[] bytes = bf.array();
//System.out.println("start..............");
String str = new String(bytes, 0, length,"UTF-8");
System.out.println(str);
//System.out.write(bytes, 0, length);
//System.out.println("end................");
System.out.println("限制是:" + bf.limit() + "容量是:" + bf.capacity() + "位置是:" + bf.position());
}
//System.out.println(str);
channel.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
<a name="7OLe7"></a>
#### 内存映射
- MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) 将文件的一个区域映射到内存中。
- mode, FileChannel.MapMode 类中的常量READ_ONLY,READ_WRITE或者PRIVATE之一
- position 映射区域的起始位置
- size 映射区域的大
```java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class NIOTest {
public static void main(String[] args) {
mmapTest();
}
/**
* 使用直接缓冲区完成文件的复制(内存映射文件)
* 耗费时间:142
*/
private static void mmapTest() throws IOException {
long startTime = System.currentTimeMillis();
FileChannel inChannel = FileChannel.open(Paths.get("E:\\1.txt"), StandardOpenOption.READ);
FileChannel outChennel = FileChannel.open(Paths.get("E:\\2.txt"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
//内存映射文件(什么模式 从哪开始 到哪结束)
MappedByteBuffer inMappeBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outMappeBuf = outChennel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
//直接都缓冲区进行数据的读写操作
byte[] dst = new byte[inMappeBuf.limit()];
inMappeBuf.get(dst);
outMappeBuf.put(dst);
inChannel.close();
outChennel.close();
long end = System.currentTimeMillis();
System.out.println("nioCopyTest2耗费时间:"+(end-startTime));
}
}
文件锁定
java.io.channels.FileChannel
- FileLock lock()
文件复制
使用FileChannel进行文件复制默认使用sendfile系统调用,如果系统内核不支持 Sendfile,则以 mmap 的零拷贝方式进行内存映射,这种情况下目的通道必须是 FileChannelImpl 或者 SelChImpl 类型。如果以上两步都失败了,基于传统的 I/O 方式完成读写。
java.io.channels.FileChannel
- transferFrom
- transferTo ```java import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption;
public class NIOTest {
public static void main(String[] args) {
readNIO();
}
/**
*
* 零拷贝模式
*
*/
private static void nioCopyTest2() throws IOException { long startTime = System.currentTimeMillis();
FileChannel inChannel = FileChannel.open(Paths.get("E:\\ 1.avi"), StandardOpenOption.READ);
FileChannel outChennel = FileChannel.open(Paths.get("E:\\ 13.avi"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
outChennel.transferFrom(inChannel,0,inChannel.size());
long end = System.currentTimeMillis();
System.out.println("nioCopyTest3耗费时间:"+(end-startTime));
}
/**
* 非直接缓冲区 文件的复制
* 耗费时间:1417
* @throws IOException
*/
private static void nioCopyTest1()throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fileInputStream = new FileInputStream(new File(“E:\ 1.avi”)); FileOutputStream fileOutputStream = new FileOutputStream(“E:\ 11.avi”);
//获取通道
FileChannel inChannel = fileInputStream.getChannel();
FileChannel outChanel = fileOutputStream.getChannel();
//分配缓冲区的大小
ByteBuffer buf = ByteBuffer.allocate(1024);
//将通道中的数据存入缓冲区
while (inChannel.read(buf) != -1) {
buf.flip();//切换读取数据的模式
outChanel.write(buf);
buf.clear();
}
outChanel.close();
inChannel.close();
fileInputStream.close();
fileOutputStream.close();
long end = System.currentTimeMillis();
System.out.println("nioCopyTest1耗费时间:"+(end-startTime));
} }
<a name="d2G9H"></a>
# 网络IO
[https://www.jianshu.com/p/da4a806e599b](https://www.jianshu.com/p/da4a806e599b)<br />Java网络编程:[https://www.liaoxuefeng.com/wiki/1252599548343744/1319099982413858](https://www.liaoxuefeng.com/wiki/1252599548343744/1319099982413858)
<a name="dXi0d"></a>
# 文件
`File`对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个`File`对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个`File`对象,并不会导致任何磁盘操作。只有当我们调用`File`对象的某些方法的时候,才真正进行磁盘操作。**从Java7开始引入了path与Files类来操作文件,比之前的File类要方便的多。**
```java
package file;
import java.io.File;
public class TestFile {
public static void main(String[] args) {
File f = new File("/root/Test.java");
System.out.println("Absolute path is:" + f.getAbsolutePath());
System.out.println("Is file exist:" + f.exists());
System.out.println("Is file Directory:"+f.isDirectory());
System.out.println("Is file:" + f.isFile());
f.setLastModified(0);
System.out.println("File:" + f.lastModified());
File[] fs = f.listFiles(); // 返回当前文件夹下文件
String parentName = f.getParent(); // 返回当前文件目录
f.mkdir(); // mkdir
f.mkdirs(); // mkdir -p
f.createNewFile(); // create new file
}
}
java.nio.file.Paths
- static Path get(Srting first, String.. more) ,从给定的连接串创造一个Path
java.nio.file.Path
- toFile() 从该路径中获取File对象
java.io.File
- Path toPath() 从该文件创建一个File对象
java.nio.file.Files
- 读写文件
- 创建文件
- 移动复制删除文件
- 读取文件信息
随机访问文件
RandomAccessFile类可以在文件中任意位置查找或者写入数据,因为磁盘文件都是随机访问的,但是网络套接字却不是。
java.io.RandomAccessFile
- RandomAccessFile(String file, String mode)
- RandomAccessFile(Filefile, String mode)
- file 要打开的文件
- mode “r”表示只读模式, “rw”表示读写模式,”rws”对数据和元数据写磁盘操作进行同步的读写,”rwd” 仅对数据写磁盘操作进行同步的读写
- long get FilePointer() 返回文件指针的当前位置
- void seeklong(pos) 将文件指针设置到距文件开头pos个字节处
-
ZIP文件
ZIP文档通常以压缩格式存储了一个或者多个文件,每个zip文档都有一个头,包含诸如每个文件名字何所使用的压缩方法等信息。
java.util.zip.ZipInputStream ZipInputStream(InputStream in) 从给定的InputStream向其中填充数据
- ZipEntry getNextEntry() 获取下一个ZipEntry对象
java.util.zip.ZipOutputStream
- ZipInputStream(OutputStream out) 将一个压缩数据写到指定的ZipOutputStream
java.nio.file.FileSystems
- 创建一个Zip文件系统来处理文件
参考
https://baijiahao.baidu.com/s?id=1652600456880754419&wfr=spider&for=pc