Java基础教程:IO流与文件基础
Java:IO流与文件基础
说明:
本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦。
走进流
什么是流
流:指的是从源到目的地的字节的有序序列。

在Java中,可以从其中读取一个字节序列的对象称作 输入流,可以向其中写入一个字节序列的对象称作 输出流。
☑ 这些字节序列的来源可以是:文件、网络连接、内存块等。
☑ 抽象类InputStream和OutputStream是构成输入/输出(I/O)的基础。
☑ 因为面向字节的流不便于处理以Unicode形式存储的信息(字符),所以从抽象类Reader 和 Writer中继承出来一个专门处理字符流的类层次结构。
☑ 适配器类InputStreamReader将InputStream转换为Reader,OutputStreamWriter将OutputStream转换为Writer
IO流家族体系
对流的分类
☑ 依据流相对于程序的另一个端点的不同:
☐ 节点流(全黄):以特定源(如磁盘文件、内存某区域或线程之间的管道)为端点构造的输入/输出流
☐ 过滤流(半黄):以其他已存在的流为端点构造的输入/输出流。
☑ 依据流中的数据单位不同:
☐ 字节流:流中的数据以8位字节为单位进行读写,以InputStream和OutputStream为共同父类
☐ 字符流:流中的数据以16位字符为单位进行读写,以Reader和Writer为共同父类
家族体系图(原创)

家族体系的顶层方法
顶层方法不是很多,但是需要我们去记住,下面列出了所有的顶层方法,遇到问题是结合上图和下表可以清理思路。
A.abstract class OutputStream
| 返回类型 | 方法及解释 |
|---|---|
| void | close() 关闭此输出流并释放与此流有关的所有系统资源。 |
| void | flush() 刷新此输出流并强制写出所有缓冲的输出字节。 |
| void | write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。 |
| void | write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 |
| abstract void | write(int b) 将指定的字节写入此输出流。 |
B.abstract class InputStream
| 返回类型 | 方法及解释 |
|---|---|
| int | available() 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 |
| void | close() 关闭此输入流并释放与该流关联的所有系统资源。 |
| void | mark(int readlimit) 在此输入流中标记当前的位置。 |
| boolean | markSupported() 测试此输入流是否支持 mark 和 reset 方法。 |
| abstract int | read() 从输入流中读取数据的下一个字节。 |
| int | read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 |
| int | read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。 |
| void | reset() 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。 |
| long | skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。 |
C.abstract class Reader
| 返回类型 | 方法及解释 |
|---|---|
| abstract void | close() 关闭该流并释放与之关联的所有资源。 |
| void | mark(int readAheadLimit) 标记流中的当前位置。 |
| boolean | markSupported() 判断此流是否支持 mark() 操作。 |
| int | read() 读取单个字符。 |
| int | read(char[] cbuf) 将字符读入数组。 |
| abstract int | read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。 |
| int | read(CharBuffer target) 试图将字符读入指定的字符缓冲区。 |
| boolean | ready() 判断是否准备读取此流。 |
| void | reset() 重置该流。 |
| long | skip(long n) 跳过字符。 |
D.abstract class Writer
| 返回类型 | 方法及注释 |
|---|---|
| Writer | append(char c) 将指定字符添加到此 writer。 |
| Writer | append(CharSequence csq) 将指定字符序列添加到此 writer。 |
| Writer | append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer.Appendable。 |
| abstract void | close() 关闭此流,但要先刷新它。 |
| abstract void | flush() 刷新该流的缓冲。 |
| void | write(char[] cbuf) 写入字符数组。 |
| abstract void | write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 |
| void | write(int c) 写入单个字符。 |
| void | write(String str) 写入字符串。 |
| void | write(String str, int off, int len) 写入字符串的某一部分。 |
输出输入流的嵌套
说明
单独使用节点流的情况在程序中较少出现。
一般常通过过滤流将多个流套接在一起,利用各种流的特性共同处理数据,套接的多个流构成了一个流链
优点:
方便数据的处理并提高处理的效率。

着重介绍的几个过滤流
☑ BufferedInputStream
☐ 在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
☐ 在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。
☑ BufferedOuputStream
☐ 该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
☑ BufferedReader和BufferedWriter同样也是提供缓存区。
☑ DataInputStream
☐ 包含用于读取基本类型数据的全部接口
说明:所有的这些在下面我们都会重新强调并实现。
常用流
思维导图

文件流
文件流包括
☐ FileReader/FileWriter类
☐ FileInputStream/FileOutputStream类
创建文件流
☐FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
☐FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
实例
public class FileCopy{
public static void main(String[] args) throws IOException{
FileInputStream in=new FileInputStream("FileCopy.java");
FileOutputStream out=new FileOutputStream("FileCopy.txt");
int c;
while( (c=in.read())!=-1)
out.write(c);
in.close();
out.close();
}
}
缓存流
说明:
缓存流是过滤流,以InputStream/OutputStream为前端流,并可指定缓冲区大小,如:
public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
BufferedReader增加readLine()
BufferedWriter增加newLine():写入一个换行符。
演示:
public class BufferedIO{
public static void main(String[] args) throws IOException{
BufferedReader in=new BufferedReader(
new FileReader("BufferedIO.java"));
PrintWriter out=new PrintWriter( new BufferedWriter(
new FileWriter("BufferedIO.txt")));
String s;
int linecnt=1;
StringBuilder sb=new StringBuilder();
while((s=in.readLine())!=null){
sb.append(linecnt+":"+s+"\n");
out.println(linecnt+":"+s);
linecnt++;
}
in.close();
out.close();
System.out.print(sb.toString());
}
}
说明:
PrintWriter
向文本输出流打印对象的格式化表示形式,即在写入的同时可以对写入的数据进行格式化。
数据流
数据流包括:
DataInputStream/DataOutputStream类
读写基本数据类型的接口方法:

演示:
public class DataIO{
public static void main(String[] args) throws IOException{
DataOutputStream out=new DataOutputStream(
new BufferedOutputStream(new FileOutputStream("data.txt")));
out.writeBoolean(false); out.writeChar('c');
out.writeByte(1); out.writeShort(2);
out.writeInt(3); out.writeLong(4L);
out.writeFloat(5.0f); out.writeDouble(6.0);
out.writeUTF("hello world!"); out.close();
DataInputStream in=new DataInputStream(
new BufferedInputStream( new FileInputStream("data.txt")));
System.out.println(in.readBoolean()+";"+in.readChar()+";");
System.out.println(in.readByte()+";"+in.readShort()+";");
System.out.println(+in.readInt()+";"+in.readLong());
System.out.println(in.readFloat()+";"+in.readDouble()+";");
System.out.println(in.readUTF()); in.close();
}
说明:
☑readUTF()与writeUTF()
writeBytes(String)和writeChars(String)方法在DataInputStream中没有对应的方法恢复出String
用DataOutputStream写字符串并使得DataInputStream能恢复出字符串的方法是使用writeUTF()和readUTF()
☑ UTF-8
ASCII字符→单字节形式;非ASCII字符→多字节形式
字符串长度→UTF-8字符串的前两字节中
Java中使用的是UTF-8的变体,UTF-8只是读写过程中的字符串形式,程序中Unicode
标准IO:
标准输入:键盘
标准输出:加载Java程序的命令窗口
Java在System类中定义了三个标准I/O流,是System类的三个静态变量:
☐System.in(public static final InputStream in):标准输入流
☐System.out(public static final PrintStream out):标准输出流
☐System.err(public static final PrintStream err):标准错误输出流

程序从键盘读入数据:
☐ int ch=System.in.read();
☐ System.in.read()从键盘缓冲区读入一个字节的数据,返回的是整型值(低位字节为输入数据,高位字节全为零)
☐ System.in.read()的执行使得整个程序被挂起,直到用户从键盘输入数据才继续运行
☐ 从键盘逐行读入:嵌套BufferedReader和InputStreamReader
实例:
public class StandardIO {
public static void main(String[] args) {
String s;
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Please input: ");
try {
s = in.readLine();
while (!s.equals("exit")) {
System.out.println(" read: " + s);
s = in.readLine();
}
System.out.println("End of Inputting");
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
java.util.Scanner类:从控制台读取输入
说明
Scanner sc=new Scanner(System.in);
Scanner将控制台输入按照分隔符模式进行分割,分隔符模式默认为匹配空格
扫描结果通过各种next*()方法转化为不同类型的值
next() 获取一个字符串
nextByte() 获取一个byte类型的整数
nextShort() 获取一个short类型的整数
nextInt() 获取一个int类型的整数
nextLong() 获取一个long类型的整数
nextFloat() 获取一个float类型的数
nextDouble() 获取一个double类型的数
nextLine() 获取一行文本(即以回车键为结束标志)
输入输出的重定向
System.setIn(InputStream)
System.setOut(PrintStream)
System.setErr(PrintStream)
随机存取文件
说明
到目前为止所学习的Java流式输入/输出都是顺序访问流,即流中的数据必须按顺序进行读写当需要随机读写磁盘文件中的内容时,用RandomAccessFile类(既可对文件读,又可对文件写)
RandomAccessFile与其他顶层类的关系

构造方法
| 构造方法摘要 |
|---|
| RandomAccessFile(File file, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 |
| RandomAccessFile(String name, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 |
| mode值 | 含意 |
|---|---|
| "r" | 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 |
| "rw" | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 |
| "rws" | 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 |
| "rwd" | 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 |
操作
文件指针操作
long getFilePointer() //返回当前文件指针
void seek(long pos) //文件指针定位到指定位置
long length() //返回文件长度
int skipBytes(int n) //从当前位置开始跳过n字节
读操作(实现了DataInput接口)
readBoolean(), readChar(), readInt(), readLong(), readFloat(), readDouble(), readLine(), readUTF()等
写操作(实现了DataOutput接口)
writeBoolean(), writeChar(), writeUTF(), writeInt(), writeLong(), writeFloat(), writeDouble()等
实例
public class RandomAccessTest {
public static void main(String[] args) throws IOException {
long filePoint = 0;
String s;
RandomAccessFile file = new RandomAccessFile(
"RandomAccessTest.java", "r");
long fileLength = file.length(); // 获取文件长度
while (filePoint < fileLength) {
s = file.readLine(); // 读一行字符,并移动文件指针
System.out.println(s); // 输出显示读入的一行字符
file.skipBytes(5);
filePoint = file.getFilePointer(); // 获取当前文件指针
}
file.close();
}
}
对象的串行化
将对象保存到外存,称为对象的永久化。对象永久化的关键是将对象的状态以一种串行格式表示出来,以便以后读取能够将该对象重构出来。对Java对象的这一读写过程称为对象的串行化。
常在下列情况下使用
1.Java远程方法调用(Remote Method Invocation)
2.Java Bean / EJB
3.对象永久化
实现串行化
• 用ObjectOutputStream/ObjectInputStream实现对象的串行化
◇ 通过ObjectOutputStream的writeObject方法将一个对象写入到流中
▪ public final void writeObject(Object obj) throws IOException
◇ 通过ObjectInputStream的readObject方法将一个对象从对象流中读出
▪ public final Object readObject() throws IOException, ClassNotFoundException
◇ ObjectOutputStream实现了java.io.DataOutput接口
◇ ectInputStream实现了java.io.DataInput接口
实例
/*输出对象*/
public class SerializeDate {
SerializeDate( ){
Date d = new Date( );
try {
ObjectOutputStream s= new ObjectOutputStream(
new FileOutputStream(“date.ser”));
s.writeObject(d);
s.close( );
}catch( IOException e){
e.printStackTrace( );
}
}
public static void main(String args[]){
SerializeDate b = new SerializeDate();
}
}
/*输入对象*/
public class UnSerializeDate {
Date d = null;
UnSerializeDate() {
try {
ObjectInputStream s = new ObjectInputStream(
new FileInputStream("date.ser"));
Object o=s.readObject();
if(o instanceof Date)
d = (Date) o;
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
UnSerializeDate us = new UnSerializeDate();
System.out.println(us.d.toString());
}
}
注意:
一个类只有实现了Serializable接口,其对象才是可串行化的
(未完待续.....)
Java基础教程:IO流与文件基础的更多相关文章
- Java:IO流与文件基础
Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...
- java 后台通过IO流把文件传到前端并下载
我的业务需求是两个不同的web程序放在不同的服务器上,web程序A要访问到web程序B上传上来的文件,所以用到了这一个IO读取文件的接口 JAVA代码(排版有点问题 已经尽力补救了(:3_ヽ)_) ...
- Java中常用IO流之文件流的基本使用姿势
所谓的 IO 即 Input(输入)/Output(输出) ,当软件与外部资源(例如:网络,数据库,磁盘文件)交互的时候,就会用到 IO 操作.而在IO操作中,最常用的一种方式就是流,也被称为IO流. ...
- java中的IO流之文件复制
O(∩_∩)O哈哈~ 1.综述 一门成熟的语言肯定具备的几个模块:IO,通信,线程,UI...... Java作为一门成熟的程序语言,其IO流是比较复杂的.上个图大家感受下: 简单分析一下,IO分为两 ...
- java用字符io流复制文件
一.小文件一次快速读写 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExceptio ...
- java中的IO流读取文件
1 InputStream类和OutputStream类 InputStream.read()方法从文件中读取一个字节(0-255),然后将此字节转换成对应的整数返回.假设一个文件的编码为utf-8编 ...
- java中使用IO流复制文件
public class TestIO { public static void main(String[] args) { // TODO Auto-generated method stub tr ...
- Java基础 IO流的文件和目录的五类主要操作
笔记: /** IO流的 文件和目录的操作 * 1.路径需要 需要两个反斜杠 或者一个单斜杠! * 绝对路径:包括盘符在内的完整的路径名! * 相对路径:在当前目录文件下的路径! * 2.File 是 ...
- java基础之IO流(二)之字符流
java基础之IO流(二)之字符流 字符流,顾名思义,它是以字符为数据处理单元的流对象,那么字符流和字节流之间的关系又是如何呢? 字符流可以理解为是字节流+字符编码集额一种封装与抽象,专门设计用来读写 ...
随机推荐
- row_number()over函数的使用(转)
(转)http://hi.baidu.com/122439049/blog/item/0c9c48131b2734d5f7039e13.html row_number() OVER (PARTITIO ...
- 第一篇:《UNIX 网络编程 第二版》编译环境的搭建
第一步:搭建基本的编译环境 安装gcc, g++, bulid-essential等编译软件 第二步:下载本书示例源码包 第三步:解压下载到的包并放在用户主目录中 第四步:进入包内并执行以下命令 su ...
- java基础---->java多线程之Join(二)
如果主线程想等待子线程执行完成之后再结束,就可以使用join方法了.它的使用是等待线程对象销毁.今天我们就通过实例来学习一下多线程中join方法的使用.草在结它的种子,风在摇它的叶子.我们站着,不说话 ...
- mysql 效率 inner join 与 where in
-- report 123.77k行 report_loss 620 行 -- inner join ;report_loss 索引 all report 索引 eq_ref ; -- total 0 ...
- String() 函数把对象的值转换为字符串。
var test1 = new Boolean(1);var test2 = new Boolean(0);var test3 = new Boolean(true);var test4 = new ...
- shell用curl抓取页面乱码,参考一下2方面(转)
1.是用curl抓取的数据是用类似gzip压缩后的数据导致的乱码.乱码:curl www.1ting.com |more乱码:curl -H "Accept-Encoding: gzip&q ...
- Think PHP递归重新排序无限极子分类数组(递归无限极分类)
Think PHP递归重新排序无限极子分类数组 // 递归重新排序无限极子分类数组 function recursive($array,$pid=0,$level=0){ $arr = array() ...
- mysql查看线程详解(转载)
如果有 SUPER 权限,则可以看到全部的线程,否则,只能看到自己发起的线程(这是指,当前对应的 MySQL 帐户运行的线程). mysql> show processlist; +—–+——— ...
- pta 习题集 数列求和-加强版
给定某数字AA(1≤A≤91≤A≤9)以及非负整数NN(0≤N≤1000000≤N≤100000),求数列之和S=A+AA+AAA+⋯+AA⋯AS=A+AA+AAA+⋯+AA⋯A(NN个AA).例如A ...
- mendeley不能做中文批注的解决方案
mendeley是一个很好用且免费的文献管理工具,但在ubuntu系统下,对文献进行批注无法切换中文输入法,实际上对ibus是支持的,但ibus实在是太难用,大部分ubuntu用户钟爱的还是fcitx ...