Java学习笔记(44)—— IO——Stream

这里将自己学习java及其应用的一些笔记、积累分享一下,如果涉及到了文章、文字侵权,请联系我删除或调整。


一、Stream

1.1 概述

  • Stream(流)——字节数据的读写,抽象成数据在管道中流动
  • Stream是单方向的:

输入流,只能用来读取数据

输出流,只能用来输出数据

  • 数据只能从头到尾顺序流动一次

二、InputStream / OutputStream

2.1 概述

  • InputStream / OutputStream 是字节流的抽象父类

2.2 输出方法

  • write(int b)

int的四个字节,只输出末尾的一个字节

[1][2][3][4] ——> [4]

  • write(byte[], from, length)

输出数组中,from 开始的 length 个字节

2.3 输入方法

  • read()

读取一个字节值,再补三个0字节,转成int。

当文件读取结束时,再读取,得到 -1

三、FileInputStream / FileOutputStream

3.1 概述

  • 是 InputStream / OutputStream字节流子类
  • 文件流,直接插在文件上,可直接读写文件数据

3.2 练习:FileOutputStream测试

package IO_Stream文件流;

import java.io.FileOutputStream;
import java.io.IOException;

public class Test1_FOS_write {
	public static void main(String[] args) throws IOException{
		System.out.println("");
		/*	不管指定的文件是否存在,都会新建空文件
		 *	路径中的文件夹必须已存在,否则抛异常
		 */
		FileOutputStream out = new FileOutputStream("d:/f2.txt");
		
		out.write(97);// 00 00 00 61 =>真正输出的只有Int的最后一个字节61
		out.write(99);// 00 00 00 63 =>真正输出的只有Int的最后一个字节63
		out.write(356);// 00 00 01 64 =>真正输出的只有Int的最后一个字节64,
					   // 数据被截断,导致数据丢失
		out.write(0x00d6);// 00 00 00 d6 => d6
		out.write(0x00d0);// 00 00 00 d0 => d0
		
		byte[] a= {101,102,103,104,105,
					110,112,113,114,115};
		
		out.write(a,0,10);// 输出byte[]数组a中,0下标开始的10个字节值
		out.write(a,3,5);// 输出byte[]数组a中,3下标开始的5个字节值
		out.close();// 释放系统资源
	}
}

3.3 练习:FileIutputStream测试

package IO_Stream文件流;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Test2_FIS_read {
	public static void main(String[] args) throws IOException {
		FileInputStream in = new FileInputStream("d:/f2.txt");
		
		int b;
		// **习惯性的遍历读取文件字节值的方法**
		// 嵌套小括号读取
		while ((b=in.read())!=-1) {
			System.out.println(b);
		}
		in.close();
	}
}

四、InputStream / OutputStream

4.1 概述

4.2 方法

  • write(int b)
  • write(byte[], from, length)
  • read()

读取一个字节,补三个0字节转成int

读取结束再读取,返回-1

  • read(byte[] buff)

按数组长度,读取一批字节值,放入数组,

并返回这一批的字节数量

读取结束再读取,返回-1

4.3 练习:读取文件字节数据

package Stream文件流;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

public class Test1_Stream文件流_read方法测试 {
	public static void main(String[] args) throws IOException {
		// f2文件共20个字节,数组长度用6,故意让最后一批放不满
		FileInputStream in = new FileInputStream("d:/f2.txt");
		
		byte[] arr = new byte[6];
		int n;// 用来存储每次read的返回值,即本次读取了多少个数据 
		
		// 固定格式,小括号嵌套,将读取语句放入嵌套的括号内
		while((n = in.read(arr)) != -1) {
		System.out.println(n+"个:"+Arrays.toString(arr));
		}
		
	}
}

4.4 练习:文件复制

package Stream文件流;
// 文件复制是字节值的复制,所以不仅仅限于文本,而BufferedReader是字符读入,只可参与字符(文本)复制
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;

public class Test2_文件复制 {
	public static void main(String[] args) {
		// 用户输入欲复制的文件的路径
		System.out.println("源文件路径:");
		String s1 = new Scanner(System.in).nextLine();
		File from = new File(s1);
		// 判断路径是否为一个文件,因为不复制文件夹
		if(!from.isFile()) {
			System.out.println("请输入一个正确的文件名!");
			return;
		}
		
		// 用户输入欲保存的目标文件的路径及文件名
		System.out.println("目标文件路径:");
		String s2 = new Scanner(System.in).nextLine();
		File to = new File(s2);
		// 判断是否为一个文件,复制的数据不能保存为一个“文件夹”
		if(to.isDirectory()) {
			System.out.println("请输入一个具体的文件,不能是文件夹!");
			return;
		}
		
		try {
			copy(from, to);
			System.out.println("完成复制!");
		} catch (Exception e) {
			System.out.println("复制出错!");
			e.printStackTrace();
		}
		
	}

	// 复制
	private static void copy(File from, File to) throws IOException {
		/*
		 *	FIS--from
		 *	FOS--to 
		 */
		// 创建数据的输入、输出流
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		
//		// 单字节读写,对硬件设备利用率低,读取、输入效率不高
//		int b;
//		while((b = in.read())!= -1) {// 从源文件依次读取一个字节
//			out.write(b);// 将读取到的一个字节写入目标文件
//		}
		
		// 批量读写文件数据
		// 批量读取时,惯用数组大小时8K=8192
		byte[] arr = new byte[8192];
		int n;// 保存每次读取数据的个数
		
		while((n = in.read(arr)) != -1) {
			/*
			 *	.write(b, off, len);
			 *	输出b,从下标off开始,输出len个 
			 */
			out.write(arr,0,n);
		}
		
		// 释放系统资源
		in.close();
		out.close();
	}
}

五、ObjectInputStream / ObjectOutputStream

5.1 概述

  • 对象的序列化、反序列化
  • 把对象的信息,按照固定的字节格式,转成一串字节序列,输出

​​​​​​​​​​​​​​​​​​​​​class A{

    int id;

   string name;

   string gender;

   int age;

}

序列化后,为一串以下字符串:

变量值      变量         类名

  xxxx       xxxxx      xxxxxx ……(字节序列)

5.2 方法

  • writeObject(Object obj)

序列化输出对象

  • readObject()

反序列化恢复对象

5.3 接口

  • 被序列化的对象,必须实现 Serializable 接口。
  • Serializable 接口

空接口;

标识接口,标识一个类,可以被序列化。

5.4 不序列化的成员

  • static ,静态属于类,不随对象一起被序列化输出

  • transient (临时),只在程序运行期间,在内存中临时存在,不随对象一起被序列化持久保存

5.5 序列化版本

  • 序列化版本,用于控制旧版本数据,不允许恢复成新版本的类型。可自己定义,也可有编译器自动添加。

static final long serialVersionUID

  • 自己不定义,编译器会添加默认版本id

根据类的定义信息,计算产生一个id

5.6 练习:Student类序列化输出与读取

package 序列化;

import java.io.Serializable;
//Serializable是一个空接口,没有抽象方法的定义;起一个标识的作用。
public class Student implements Serializable{
	// ctrl + 1,序列化版本,其值可以自己定义,也可由编译器产生,如不手动添加,则编译器自动生成
	// generated的方法,与编译器默认添加的方法相同,通过类的代码信息计算产生,其值只与类的代码信息有关
	private static final long serialVersionUID = -1754877342732270289L;
	
	private int id;
	private String name;
	// 静态和临时,不会被序列化持久存储
	transient private int age;// transient-临时
	static private String gender;// static-静态
	
	public Student() {
	}

	public Student(int id, String name, int age, String gender) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]";
	}
}
package 序列化;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Test1_Student类序列化输出测试 {
	public static void main(String[] args) throws IOException, Exception {
		Student s = new Student(1,"Alice",19,"F");
		
		/*	
		 *	Student对象--OOS--FOS--f3文件 ,创建输出流,字节值输出到文件
		 *	OOS--FOS流衔接,配合完成
		 */
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("d:/课程项目的临时文件/f3"));
		// ObjectOutputStream中的writeObject方法实现序列化输出
		out.writeObject(s);
		out.close();
	}
}
package 序列化;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Test2_Student类序列化读取测试 {
	public static void main(String[] args) throws IOException, Exception {

		ObjectInputStream in = new ObjectInputStream(new FileInputStream("d:/课程项目的临时文件/f3"));
		/*	Student对象在序列化写入f3时,保存了原有的类名,变量,变量值等信息。
		 * 	f3的字节码在,反序列化方法readObject中已经被重新创建为Student对象
		 *	但是,其方法返回值为Object对象,所以需要向下转型 
		 */
		Student s= (Student) in.readObject();
		in.close();
		System.out.println(s);
	}
}

六、字符编码、字符集

6.1 概述

  • ASC-II

0 127

英文字符、标点,及指令字符

  • iso-8859-1Latin-1

扩展到 255

  • cjk 字符集 - 中日韩字符集统称

双字节编码,到 65535

  • 中国国标码GBK

包含 21003 中文字符

  • Unicode 编码

统一码、万国码

100+ 编码位

常用字符表 - 双字节

生僻字符表 - 三字节,或以上

  • UTF-8

Unicode 的传输格式

Unicode Transfermation Format

英文 - 单字节

某些字符 - 双字节

中文 - 三字节

特殊符号 - 四字节

下面我们来看几个例子:

  • Unicode

a      00 61

    4e 2d

  • GBK

a         61

中  d6 d0

  • UTF-8

a        61

 e4 b8 ad

Javachar类型字符,使用 Unicode 编码
 

6.2 Java的字符编码转换

  • Unicode <---> 其他编码
  • Unicode --> 其他编码

String s = "abc中文";

//Unicode 转成系统的默认编码

byte[] a = s.getBytes();

//Unicode 转成指定的编码

byte[] a = s.getBytes("UTF-8");

  • Unicode <-- 其他编码

//把系统默认编码的一组字节值,转成Unicode

String s = new String(byte[]);

//把指定编码的一组字节值,转成Unicode

String s = new String(byte[], "UTF-8");

6.3 练习:编码转换

package 编码转换;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Test1 {
	public static void main(String[] args) throws IOException {
		String s = "abc中文";// 在Java中都是Unicode编码,全是双字节字符
		System.out.println("Java字符串:"+s);
		// 调用方法,将字符串s转为不同的编码方式的编码
		f(s,null);
		f(s,"GBK");
		f(s,"UTF-8");
		f(s,"Unicode");
		
	}
	/*	以下称呼指代相同的东西:
	 *	编码 -- encoding
	 *	字符集 -- charset 
	 */
	private static void f(String s, String encoding) throws IOException {
		// Unicode字符串s,转换成其他编码的一组字节值
		byte[] a;
		if(encoding == null) {
			// 为提供编码方式,转为操作系统的默认编码(本系统为GBK)
			a = s.getBytes();
		}else {
			// 提供了编码方式,转为指代编码方式的编码
			a = s.getBytes(encoding);
		}
		System.out.println(encoding+"\t"+Arrays.toString(a));
		
		/*----------------------------------------------------------*/
		String str;
		if(encoding == null) {//从默认编码,转为Unicode
			str = new String(a);
		}else {//从指定编码,转为Unicode
			str = new String(a,encoding);
		}
		System.out.println(encoding+"\t"+str);	
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值