目录
IO
java.io包用来支持Java的基本IO(输入输出)系统,包括文件IO、网络Socket套接字、等等。
IO流的概念
IO:即对输入流,输出流的读写操作。
- 流的概念--输入流:可以将很多不同类型设备的输入---磁盘文件、网络Socket、键盘等抽象为输入流。
- 流的概念--输出流:可以将很多不同类型设备的输出---磁盘文件、网络Socket、屏幕(/输出控制台)等抽象为输出流。
IO流的表现形式,主要有两种形态。一种是字节流,一种是字符流。
- 流的形态--字节流:字节流专门处理基于字节的流(比如:二进制文件的读写时,就用字节流)。既有输入字节流,也有输出字节流。
- 流的形态--字符流:字符流专门处理基于字符的流(比如:文本文件的读写时,就用字符流)。既有输入字符流,也有输出字符流。其实在底层JVM的实现上,仍然都是基于字节流的,那Java提供的基于字符的字符流的读写操作,只是为了方便编码而设计的字符流API。
IO流的核心方法
IO流操作最核心的方法:
- read() 读取一个字节/字符 //返回当前读到的字节/字符 或者 碰到文件结束时返回-1
- read(byte[] bs) 读取若干个字节或字符
- readLine() 读取一行文本 //返回当前读到的文本行内容 或者 碰到文件末尾时返回null
- write(int b) 写入一个字节
- write(byte[] data) 写入若干个字节
- flush() 内容刷至设备
readLine()方法的缺陷:只能识别换行或者回车/换行对来当做行结束。网络编程时,假如回车是流的最后一个字符,那么readLine()会挂起,等待最后一个字符的出现,但是这个字符永远也不会出现。针对文件流进行IO编程时,这一点倒是不担心,因为文件内容读到最后一个字符回车后,在读就啥也读不到了,返回-1表示文件已结束。
flush()方法的重要性:
例如:1024字节缓冲区,里面写入了300字节的内容(内容就这么大)后,由于IO流是阻塞同步的,当缓冲区没满的时候,缓冲区中的内容是不会主动写入设备的,flush()方法可以强迫缓冲区中的300字节内容写入设备,即使此时缓冲区还没满,以此来打破IO流阻塞在这里的无限等待。。。
IO字节流
字节流 | ||
流封装的设备 | 输入字节流 | 输出字节流 |
File磁盘文件 | FileInputStream | FileOutputStream |
Object对象 | ObjectInputStream | ObjectOutputStream |
Data基本数据类型 | DataInputStream | DataOutputStream |
ByteArray字节数组 | ByteArrayInputStream | ByteArrayOutputStream |
Pipe管道 | PipeInputStream | PipeOutputStream |
字节流 | |||
输入字节流 | 输出字节流 | 一般用法 | |
抽象类 | InputStream --read(int b) --read(byte[] data) | OutputStream --write(int b) --write(byte[] data) | 字节流的超类,一般用作对象引用,表示流是输入流还是输出流。 |
缓冲器 | BufferedInputStream -- --它没有定义任何新的方法,只是重写了InputStream的方法 | BufferedOutputStream -- --它没有定义任何新的方法,只是重写了OutputStream的方法 | new BufferedInputStream( InputStream in ); |
new BufferedOutputStream( OutputStream out ); | |||
语法器 | PushbackInputStream | new PushbackInputStream( InputStream in ); | |
合成器 | SequenceInputStream | new SequenceInputStream( Enumeration<? extends InputStream> e ); | |
打印器 | PrintStream | new PrintStream( OutputStream out ); |
PrintStream已被废弃,新编写的代码如果要用到这个类的话,则尽可能的转换到使用PrintWriter来编程,因为,PrintStream类有其鸡肋的问题:
1:)println()的输出是和平台相关的。windows回车/换行、unix换行、mac回车
2:)PrintStream使用所在平台的默认编码格式。
3:)PrintStream吞掉了所有的异常,这在网络编程来说是个灾难。
字节流的一般运用结构:
//读:1个字节
try{
new inObj; //初始化流对象
do{ //从流中读出字节
int k = inObj.read(); //或者 int k = inObj.read(byte[] bs);
if( -1!=k ) {
//消费字节k
}
}while( -1!=k );
}catch(Exception e){}
//读:N个字节
try{
new inObj; //初始化流对象
byte[] bs = new byte[N]; //初始化字节数组
do{ //从流中读出字节
int k = inObj.read(byte[] bs);
if( -1!=k ) {
//消费字节数组bs
}
}while( -1!=k );
}catch(Exception e){}
//写:
try{
new outObj; //初始化流对象
byte[] bs = new byte[N]; //初始化字节数组
outObj.write(byte[] bs); //写入内容
outObj.flush(); //内容刷至设备
}catch(Exception e){}
IO字符流
字符流 | ||
流封装的设备 | 输入字符流 | 输出字符流 |
File磁盘文件 | FileReader | FileWriter |
CharArray字符数组 | CharArrayReader | CharArrayWriter |
Pipe管道 | PipeReader | PipeWriter |
String字符串 | StringReader | StringWriter |
字符流 | |||
输入字符流 | 输出字符流 | 一般用法 | |
抽象类 | Reader | Writer | 字符流的超类,一般用作对象引用,表示流是输入流还是输出流。 |
包装器 | InputStreamReader | OutputStreamReader | new InputStreamReader( InputStream in, String charsetName ); |
new OutputStreamReader( OutputStream out, String charsetName ); | |||
缓冲器 | BufferedReader | BufferedWriter | new BufferedReader( Reader in ); |
new BufferedOutputStream( Writer out ); | |||
语法器 | PushbackReader | new PushbackInputStream( Reader in ); | |
行计数器 | LineNumberReader | new LineNumberReader( Reader in ); | |
打印器 | PrintWriter | new PrintWriter( Writer out ); |
字符流只是对字节流的封装,具体底层写入时仍然是按照字节流来写入的。例如:
writer.write("Network");
如果采用big-endian编码,底层写入的字节是:004E 0065 0074 0077 006F 0072 006B
如果采用little-endian编码,底层写入的字节是:4E00 6500 7400 7700 6F00 7200 6B00
如果采用UTF-8编码,底层写入的字节是:4E 65 74 77 6F 72 6B
字符流的一般运用结构:
//读:1个字符
try{
new inObj; //初始化流对象
do{ //从流对象逐个读出字符
int k = inObj.read();
if( -1!=k ) {
//消费char(k)
}
}while( -1!=k );
}catch(Exception e){}
//读:1行文本
try{
new inObj; //初始化流对象
do{ //从流对象逐行读取文本
String line = inObj.readLine();
if( null!=line ) {
//消费line
}
}while( null!=line );
}catch(Exception e){}
//写
try{
new outObj; //初始化流对象
outObj.write("nihao"); //写入内容
outObj.newLine(); //写换行符
outObj.flush(); //内容刷至设备
}catch(Exception e){}
IO流的示例
上图反应的是,常见的IO流处理时的层层包装后的编程手法。
File类
文件读写
创建目录、文件
删除目录、文件
判断目录、文件是否存在
An abstract representation of file and directory pathnames. File对象代表封装了一个文件或者目录,这样我们即可通过File对象来进行文件/目录的访问操作。File类提供了大量的方法供我们使用,常用的有:
getAbsoluteFile() | 获取绝对路径全称的File对象 |
isAbsolute() | 是否绝对路径 |
mkdirs() | 创建目录 |
createNewFile() | 创建文件 |
delete() | 删除文件/目录 |
exists() | 文件/目录是否存在 |
isDirectory() | 是否是目录 |
isFile() | 是否是文件 |
canWrite() | 文件是否可写 |
canRead() | 文件是否可读 |
canExcute() | 文件是否可执行 |
isHidden() | 文件是否隐藏 |
getName() | 得到文件/目录的名称 |
getParent() | 得到文件/目录之前的父路径的全名称 |
getPath() | 得到File对象封装的字符串形式 |
listFiles() | 罗列目录下的直接孩子(不递归孩子的孩子...) |
listFiles(FileFilter filter) | 罗列path目录下的直接孩子,有过滤器,FileFilter函数式接口(不递归孩子的孩子...) |
listFiles(FileFilter filter, String fileName) | 罗列path目录下的直接孩子,有过滤器,匹配文件名fileName的(不递归孩子的孩子...) |
toPath() | 互通NIO模式,从java.io.File对象转变成java.nio.file.Path对象 |
文件名、文件路径、文件目录、文件大小、文件是否存在,目录是否存在,创建目录,创建文件,读文件,写文件,重命名文件,文件拷贝,文件删除,....等等若干需要的操作,请参考:文件小示例demo