Java IO使用总结

Java IO 总结

IO 是什么?其实就是Java中的一种输入和输出功能,也可以理解为对文件的写入和读出的操作。Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出源抽象表述为”流”。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
流有输入和输出,输入时是流从数据源流向程序。输出时是流从程序传向数据源,而数据源可以是内存,文件,网络或程序等。

在Java中有输入、输出两种IO流,每种输入、输出流又分为字节流和字符流两大类。


Java IO.png

在介绍IO流之前,我们先明白Java中字节和字符的关系。

1.字节与字符

1.1 概念
  • 字节:每个字节(byte)有8bit组成
  • 字符:一个汉字或者英文字母
1.2 两者关系

Java采用unicode编码,2个字节来表示一个字符,而一个字符表示一个汉字或英文字母,具体字符与字节之间的大小转换视编码情况而定,这些不是我们需要关心的事情,我们只需要知道不同的编码对应的转换规则不一样。有时候读取的数据是乱码,就是因为编码方式不一致,需要进行转换,然后再按照unicode进行编码。

getBytes(String charsetName)使用指定的编码方式将此String编码为 byte 序列,并将结果存储到一个新的 byte 数组中。如果不指定将使用操作系统默认的编码方式,我的电脑默认的是GBK编码。

 String str = "hello world 你好哦";
        int byte_len = str.getBytes().length;
        int len = str.length();
        System.out.println("字节长度为:" + byte_len);
        System.out.println("字符长度为:" + len);
// 编译工具为IDEA,输出结果如下
字节长度为:21
字符长度为:15
系统默认编码方式:UTF-8

2.IO流的分类

2.1 输入流和输出流

根据数据流向不同分为:输入流和输出流。

输入流:从流中读取数据
输出流:将数据写入到流中
输入输出流.jpg
2.2输入流和输出流

字节流和字符流和用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同。
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

2.3节点流和处理流

按照流的角色来分,可以分为节点流和处理流。
可以从/向一个特定的IO设备(如磁盘、网络)读/写数据的流,称为节点流,节点流也被成为低级流。
处理流是对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能,处理流也被称为高级流。

//节点流,直接传入的参数是IO设备
FileInputStream fis = new FileInputStream("test.txt");
//处理流,直接传入的参数是流对象
BufferedInputStream bis = new BufferedInputStream(fis);
  1. 节点流
类型 字符流 字节流
File(文件) FileReader
FileWriter
FileInputStream
FileOutputStream
Memory Array CharArrayReader
CharArrayWriter
ByteArrayInputStream
ByteArrayOutputStream
Memory Array StringReader
StringWriter
Pipe(管道) PipedReader
PipedWriter
PipedInputStream
PipedOutputStream
  1. 处理流 ,用来包装节点流
类型 字符流 字节流
Buffering BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream
Filtering FilterReader
FilterWriter
FilterInputStream
FilterOutputStream
Converting between Bytes and Characters InputStreamReader
OutputStreamWriter
Object Serialization ObjectInputStream
ObjectOutputStream
DataConversion DataInputStream
DataOutputStream
Counting LineNumberReader LineNumberInputStream
Peeking Ahead PushbackReader PushbackInputStream
Printing PrintWriter PrintStream

(1)Buffering缓冲流:在读入或写出时,对数据进行缓存,以减少I/O的次数:BufferedReader与BufferedWriter、BufferedInputStream与BufferedOutputStream。
(2)Filtering 滤流:在数据进行读或写时进行过滤:FilterReader与FilterWriter、FilterInputStream与FilterOutputStream。
(3)Converting between Bytes and Characters 转换流:按照一定的编码/解码标准将字节流转换为字符流,或进行反向转换(Stream到Reader):InputStreamReader、OutputStreamWriter。
(4)Object Serialization 对象流 :ObjectInputStream、ObjectOutputStream。
(5)DataConversion数据流: 按基本数据类型读、写(处理的数据是Java的基本类型(如布尔型,字节,整数和浮点数)):DataInputStream、DataOutputStream 。
(6)Counting计数流: 在读入数据时对行记数 :LineNumberReader、LineNumberInputStream。
(7)Peeking Ahead预读流: 通过缓存机制,进行预读 :PushbackReader、PushbackInputStream。
(8)Printing打印流: 包含方便的打印方法 :PrintWriter、PrintStream。

3.IO流的四大基类

3.1 字符流 Reader和Writer

字符流原理:
Reader是字符输入流的父类
Writer是字符输出流的父类
字符流是以字符(char)为单位读写数据的,一次处理一个unicode
字符流的底层仍然是基本的字节流

  Reader常用方法:

   int read():读取一个字符,返回的int值“低16位”有效
   int read(char[] chs):从该流中读取一个字符数组的length个字符并存入该数组,返回值为实际读取到的字符量

  Writer的常用方法:

    void write(int c):写出一个字符,写出给定int值“低16位”表示的字符
    void write(char[] chs):将给定字符数组中所有字符写出
    void write(String str):将给定的字符串写出
    void write(char[] chs,int offset,int len):将给定的字符数组中从offset处开始连续的len个字符写出

3.2 字符输入流
  InputStream是所有字节输入流的父类,其定义了基础的读取方法,如下:
  int read():读取一个字节,以int形式返回,该int值的“低8位”有效,若返回值为-1则表示EOF
  int read(byte[] d):尝试最多读取给定数组length个字节并存入该数组,返回值为实际读取到的字节量

  OutputStream是所有字节输出流的父类,其定义了基础的写出方法,如下:

  void write(int d):写出一个字节,写的是给定的int的“低8位”
  void write(byte[] d):将给定的字节数组中的所有字节全部写出
  

4.常见用法

4.1 对象序列化
 // 创建写出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
 // 对象写出流
 ObjectOutputStream oos = new ObjectOutputStream(bos);
 // 写对象
 oos.writeObject(this);
 // 关闭
 oos.close();

 // 创建写出流
 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
 // 转成对象流
 ObjectInputStream ois = new ObjectInputStream(bis);
 personClone = (Person) ois.readObject();
 ois.close();
4.2 文件读写
// 字节流方式写出
FileOutputStream fos = new FileOutputStream("fos.txt");
String str = "Hello,World";
byte[] date = str.getBytes();
fos.write(date);
System.out.println("写出完毕");
fos.close();

// 字节流方式写入
FileInputStream fis = new FileInputStream("fos.txt");
int d = -1;
while((d=fis.read())!=-1){
    System.out.print((char)d);
}
fis.close();


4.3 转换流读写

// 转换流写入
FileOutputStream fos = new FileOutputStream("osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
osw.write("测试");
osw.close();

// 转换流读取
FileInputStream fis = new FileInputStream("osw.txt");
InputStreamReader isr = new InputStreamReader(fis,"GBK");
int d = -1;
while((d=isr.read())!=-1){
    System.out.print((char)d);
}
isr.close();

4.4 缓冲流读写

//创建缓冲字节输出流
FileOutputStream fos = new FileOutputStream("fos.txt");
//所有字节被存入缓冲区,等待一次性写出
BufferedOutputStream bos = new BufferedOutputStream(fos);
String str = "Hello Java";
byte[] date = str.getBytes();
bos.write(date);
//关闭流之前,缓冲输出流会将缓冲区内容一次性写出
bos.close();

 //创建缓冲字节输入流
FileInputStream fis = new FileInputStream("fos.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
int d = -1;
//缓冲读入,实际上并非是一个字节一个字节从文件读取
while((d=bis.read())!=-1){
    System.out.println(d);
}
bis.close();

5.总结

使用IO流通过四点来完成:

5.1 明确数据的来源和数据到达的目的地。

来源:输入流 [InputStream,Reader]。
目的:输出流 [OutputStream,Writer]。

5.2操作的数据是否是纯文本。

是:字符流,使用Reader与Writer;
否:字节流,使用InputStream与OutputStream。

5.3明确要使用哪个具体的对象。 通过设备来进行区分:

源设备:内存用数组,硬盘就加file,键盘用System.in;
目的设备:内存用数组,硬盘就加file,键盘用System.out。

5.4明确是否还需要其他额外功能:例如

(1)是否需要较高的效率,即是否需要使用缓冲区,是就加上Buffered;
(2)是否需要转换,是,就使用转换流,InputStreamReader 和 OutputStreamWriter。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352