Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题
PrintWriter打印流
Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便
同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法
PrintWriter的小例子:打印字符录入的大写
1: //读取键盘录入,打印大写
2: private static void printWriterMethod() throws IOException
3: {
4: BufferedReader bufr =
5: new BufferedReader(new InputStreamReader(System.in));
6:
7: PrintWriter out = new PrintWriter(System.out,true);
8:
9: String line = null;
10:
11: while( (line = bufr.readLine()) != null)
12: {
13: if("over".equals(line))
14: break;
15: //只需一条语句,便可打印一行数据,非常方便
16: out.println(line.toUpperCase());
17: }
18:
19: out.close();
20: bufr.close();
21: }
SequenceInputStream合并流
序列流,可将多个流合并成一个流,按序列进行读取
可手动指定各个流创建对象,也可将多个流存入集合,利用枚举Enumeration来创建对象
合并和分割流的小例子:
1: import java.io.*;
2: import java.util.*;
3:
4: class SequenceInputStreamDemo
5: {
6: public static void main(String[] args) throws IOException
7: {
8:
9: int num = splitFile(new File("pic.jpg"));
10:
11: /*
12: 合并分割后的流
13: */
14:
15: //定义Vector集合存储所有part文件的字节输入流
16: Vector<FileInputStream> v = new Vector<FileInputStream>();
17:
18: for(int i = 1 ; i <= num ; i ++ )
19: {
20: v.add(new FileInputStream(i+".part"));
21: }
22:
23: Enumeration<FileInputStream> en = v.elements();
24:
25: FileOutputStream fos = new FileOutputStream("pic1.jpg");
26:
27: //定义序列流,通过枚举合并所有的输入流
28: SequenceInputStream sis = new SequenceInputStream(en);
29:
30: byte[] buf = new byte[1024];
31:
32: int len = -1;
33:
34: while( (len = sis.read(buf)) != -1)
35: {
36: //将合并后的流写入一个文件
37: fos.write(buf,0,len);
38: }
39:
40: fos.close();
41: sis.close();
42: }
43:
44: //分割流
45: private static int splitFile(File f) throws IOException
46: {
47: FileInputStream fis = new FileInputStream(f);
48:
49: long size = f.length();
50:
51: byte[] buf = null;
52:
53: //选择缓冲区大小
54: if(size > 1024*1024*5)
55: buf = new byte[1024*1024];
56: else
57: buf = new byte[(int)size/5];
58:
59: int len = -1;
60: int count = 1;
61:
62: while( (len = fis.read(buf)) != -1)
63: {
64: //每个缓冲区的内容分别写入不同的part文件
65: FileOutputStream fos = new FileOutputStream((count++)+".part");
66: fos.write(buf,0,len);
67: fos.close();
68: }
69:
70: fis.close();
71:
72: return count-1;
73: }
74: }
对象的序列化
ObjectInputStream,ObjectOutputStream
将对象存取在硬盘上,叫做对象的持久化存储(存储的是对象的属性值,而不是方法)
想要对对象进行序列化,该对象必须实现Serializable接口,Serializable接口没有方法,称为标记接口,实现过程只是给实现者加入一个序列化的ID:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 其实就是序列号,这个序列号是由变量的声明语句自动生成的,我们也可以自己定义类的序列号
对象序列化的小例子
1: import java.io.*;
2:
3: class Person implements Serializable
4: {
5: //序列号,保证类型一致
6: static final long serialVersionUID = 42L;
7:
8: //静态变量以及transient修饰的变量不会被序列化
9: static String country = "cn";
10: transient int grade;
11: private String name;
12: private int age;
13:
14: Person(String name,int age,int grade,String country)
15: {
16: this.name = name;
17: this.age = age;
18: this.grade = grade;
19: this.country = country;
20: }
21:
22: public String toString()
23: {
24: return name+"::"+age+"::"+grade+"::"+country;
25: }
26: }
27:
28: class ObjectStreamDemo
29: {
30: public static void main(String[] args) throws Exception
31: {
32:
33: //writeObj();
34: readObj();
35: }
36:
37: //将对象写入流中
38: private static void writeObj() throws IOException
39: {
40: ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
41:
42: oos.writeObject(new Person("Shawn",30,3,"en"));
43: oos.writeObject(new Person("feng",23,6,"usa"));
44:
45: oos.close();
46: }
47:
48: //将对象从流中读出并打印
49: private static void readObj() throws Exception
50: {
51: ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
52:
53: Person p1 = (Person)ois.readObject();
54: Person p2 = (Person)ois.readObject();
55:
56: System.out.println("p1 --- "+p1);
57: System.out.println("p2 --- "+p2);
58:
59: ois.close();
60: }
61: }
我们可以看到,静态变量和transient修饰的变量是不会被序列化到硬盘上的
管道流
PipedInputStream,PipedOutputStream
管道Demo,一个线程写,一个线程读
1: import java.io.*;
2:
3: //读管道流线程
4: class Read implements Runnable
5: {
6: private PipedInputStream pis;
7:
8: Read(PipedInputStream pis)
9: {
10: this.pis = pis;
11: }
12:
13: public void run()
14: {
15: try
16: {
17: byte[] buf = new byte[1024];
18:
19: int len = -1;
20:
21: //阻塞方法,读不到数据会等待
22: len = pis.read(buf);
23:
24: System.out.println(new String(buf,0,len));
25:
26: pis.close();
27: }
28: catch (IOException e)
29: {
30: System.out.println("pipe read error!");
31: }
32:
33: }
34: }
35:
36: //写管道流线程
37: class Write implements Runnable
38: {
39: private PipedOutputStream pos;
40:
41: Write(PipedOutputStream pos)
42: {
43: this.pos = pos;
44: }
45:
46: public void run()
47: {
48: try
49: {
50: pos.write("pipe is coming!".getBytes());
51:
52: pos.close();
53: }
54: catch (IOException e)
55: {
56: System.out.println("pipe write error!");
57: }
58:
59: }
60: }
61:
62: class PipedStreamDemo
63: {
64: public static void main(String[] args) throws IOException
65: {
66: PipedInputStream pis = new PipedInputStream();
67: PipedOutputStream pos = new PipedOutputStream();
68:
69: //链接读写管道
70: pis.connect(pos);
71:
72: new Thread(new Read(pis)).start();
73:
74: new Thread(new Write(pos)).start();
75: }
76: }
随机访问文件流
RandomAccessFile
直接继承Object类,内部封装了字节输入输出流,同时封装了文件的指针,可对基本数据类型进行直接读写,最大的好处是可以实现数据的分段写入,通过seek方法。
用随机访问实现的多线程复制文件(后期会改进代码,完成多线程下载)
1: import java.io.*;
2:
3: //下载线程
4: class DownLoadThread implements Runnable
5: {
6: private RandomAccessFile in;
7: private RandomAccessFile out;
8: private int offset;//偏移量
9: private int buf_size;//分配数据量
10: private int block_size;//缓冲区大小
11:
12: //初始化
13: DownLoadThread(RandomAccessFile in,RandomAccessFile out,int offset,int buf_size)
14: {
15: this.in = in;
16: this.out = out;
17: this.offset = offset;
18: this.buf_size = buf_size;
19:
20: block_size = 1024*512;
21: if(buf_size < block_size)
22: block_size = buf_size;
23:
24: }
25:
26: public void run()
27: {
28: try
29: {
30: System.out.println(Thread.currentThread().getName()+"开始下载...");
31:
32: //读写流都偏移到指定位置
33: in.seek(offset);
34: out.seek(offset);
35:
36: byte[] buf = new byte[block_size];
37:
38: int len = -1;
39:
40: int lastSize = buf_size;
41:
42: //读取信息并写入到目的地
43: while( (len = in.read(buf)) != -1)
44: {
45: out.write(buf,0,len);
46:
47: lastSize -= len;
48:
49: //分配数据量完成,结束线程
50: if(lastSize == 0)
51: break;
52: if(lastSize < block_size)
53: {
54: block_size = lastSize;
55: buf = new byte[block_size];
56: }
57: }
58:
59: System.out.println(Thread.currentThread().getName()+"下载完成!");
60:
61: in.close();
62: out.close();
63:
64: }
65: catch (IOException e)
66: {
67: throw new RuntimeException(e);
68: }
69:
70: }
71: }
72:
73: class MutiDownLoadDemo
74: {
75: public static void main(String[] args) throws Exception
76: {
77: //确定源文件和目的文件
78: File fin = new File("1.avi");
79: File fout = new File("5.avi");
80:
81:
82: multiDownload(fin,fout,12);
83:
84:
85: }
86:
87: //多线程下载 thread_num为线程数
88: private static void multiDownload(File fin,File fout,int thread_num) throws Exception
89: {
90: RandomAccessFile in = new RandomAccessFile(fin,"r");
91:
92: RandomAccessFile out = new RandomAccessFile(fout,"rwd");
93:
94: int len = (int)fin.length();
95:
96: //确定目的文件大小
97: out.setLength(len);
98:
99: in.close();
100: out.close();
101:
102: System.out.println("-----------File size : "+(len>>20)+" MB--------------");
103: System.out.println("-----------Thread num: "+thread_num+"---------");
104:
105: //确定每个线程分配的数据量
106: int buf_size = len/thread_num;
107:
108: System.out.println("-----------buffer size: "+(buf_size>>20)+" MB-----------");
109:
110: //开启每个线程
111: for(int i = 0 ; i < thread_num ; i ++)
112: {
113: //"rwd"模式代表可读可写并且线程安全
114: new Thread(
115: new DownLoadThread(new RandomAccessFile(fin,"r"),new RandomAccessFile(fout,"rwd"),i*buf_size,buf_size)
116: ).start();
117: }
118: }
119: }
基本数据类型流对象
DataInputStream,DataOutputStream
1: public static void main(String[] args) throws IOException
2: {
3: DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
4:
5: dos.writeInt(123);
6:
7: dos.writeDouble(123.45);
8:
9: dos.writeBoolean(true);
10:
11: DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
12:
13: System.out.println(dis.readInt());
14: System.out.println(dis.readDouble());
15: System.out.println(dis.readBoolean());
16: }
内存作为源和目的的流对象
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader 与 StringWriter
字符编码
字符流出现是为了更方便的操作字符,通过InputStreamReader和OutputStreamWriter可以任意指定编码表进行解码转换
编码表
计算机开始只能识别二进制数据,为了更方便的表示各个国家的文字,就将各个国家的文字与二进制数据进行一一对应,形成了一张表,即为编码表
常见的编码表
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符
......
编码规则
只有GBK和UTF-8识别中文,GBK向下兼容GB2312
GBK两个字节表示一个字符,UTF-8是1-3个字节表示一个字符,每个字节前面1-3位作为标识头
GBK和UTF-8都兼容ASCII码表
模拟编解码过程代码
1: public static void main(String[] args) throws Exception
2: {
3: //字符串
4: String s = "你好";
5:
6: //用UTF-8编码表编码s字符串
7: byte[] b = s.getBytes("UTF-8");
8:
9:
10: System.out.println(Arrays.toString(b));
11:
12: //用GBK编码表解码
13: String s1 = new String(b,"GBK");
14:
15: //获取之后发现不是原来的字符串
16: System.out.println(s1);
17:
18: //用GBK重新编码回去
19: byte[] b1 = s1.getBytes("GBK");
20:
21: //再用UTF-8解码
22: String s2 = new String(b1,"UTF-8");
23:
24: System.out.println(s2);
25:
26:
27: }
这样做存在一个问题,由于GBK与UTF-8都支持中文,所以UTF-8编解码时有可能会去内部的相似码表去查找,这样编码出来的字符就会与原字符不符,所以一般使用ISO8859-1与中文码表互相编解码转换
一个有趣的小例子
新建一个文本文档,写入“联通”两个字,保存,关闭,再打开,发现变成了一个奇怪的字符,这是为什么呢?
首先windows默认的是ANSI编码,而UTF-8编码的标识头规则如下图
由于记事本是由编码本身的规律判断选取哪个编码表的
所以答案是,“联通”这两个字由ANSI编码之后的码流符合UTF-8的规则,则记事本自动识别是UTF-8的字符,而去查了UTF-8的码表
解决方法,我们只要在联通前面加上任意字符,记事本就不会误判为UTF-8解码了
Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题的更多相关文章
- angular学习笔记(二十八-附2)-$http,$resource中的promise对象
下面这种promise的用法,我从第一篇$http笔记到$resource笔记中,一直都有用到: HttpREST.factory('cardResource',function($resource) ...
- Java基础学习笔记二十八 管家婆综合项目
本项目为JAVA基础综合项目,主要包括: 熟练View层.Service层.Dao层之间的方法相互调用操作.熟练dbutils操作数据库表完成增删改查. 项目功能分析 查询账务 多条件组合查询账务 添 ...
- 菜鸡的Java笔记 第二十八 - java 包的定义
包的主要作用以及定义 包的导入操作 系统常见的开发包 jar 程序命令 包的定义 在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...
- Java笔记(二十六)……IO流上 字节流与字符流
概述 IO流用来处理设备之间的数据传输 Java对数据的操作时通过流的方式 Java用于操作流的对象都在IO包中 流按操作的数据分为:字节流和字符流 流按流向不同分为:输入流和输出流 IO流常用基类 ...
- Java学习笔记二十八:Java中的接口
Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...
- Java笔记(二十九)……网络编程
概述 网络模型 网络通讯的要素 ip地址:网络中设备的标识符 端口:用于标识同一台设备上不同的进程,有效端口:0~65535,其中0~1024是系统使用端口或者保留端口 TCP与UDP UDP特点: ...
- Java笔记(二十五)……其他常用API
System类 工具类全部都是静态方法 常用方法 获取系统属性信息 static PropertiesgetProperties() static StringgetProperty(String k ...
- Java笔记(二十二)……Collection集合
概述 为什么会出现集合类 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式 数组和集合类同是容器,有何不同 数组虽然也可以存储 ...
- 菜鸡的Java笔记 第十八 - java 代码块
代码块 code block content (内容) 在程序结构之中使用"{}"定义的内容就称为代码块,但是会根据其声明的位置以及关 ...
随机推荐
- php中的require() 语句的使用方法
php中的require() 语句的使用方法 require()语句包括并运行指定文件. require()语句包括并运行指定文件.有关包括如何工作的详细信息见 include() 的文档. requ ...
- js电话号码正则校验--座机和手机号
1.最新的电话号码段: 移动:134(1349除外)135 136 137 138 139 147 150 151 152 157 158 159 182 183 184 187 188 联通: 13 ...
- Android线程池的使用(未完)
ExecutorService Executors public class Executors // 创建一个线程池,使用固定数量的线程操作共享无界队列. public static Executo ...
- WPF读书笔记(第一天)
今天开始学习WPF,大家都推荐<深入浅出WPF>这本书,一下是我觉得此书中重要的地方,记录下来以便以后回顾,也希望其他人看到了对你们有帮助. 1.XAML是可扩展应用程序标记语言 是WPF ...
- hdu 1427 dfs
速算24点 题意:随机给你四张牌,包括 A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13).要求只用'+','-','*','/'运算符以及括号改变运算 顺序,使得最终 ...
- objective_C 优缺点
objective-c语言的优缺点 objc优点: 1) Cateogies 2) Posing3) 动态识别4) 指标计算5)弹性讯息传递6) 不是一个过度复杂的 C 衍生语言7) Objectiv ...
- call()和apply()的区别
var a = function(a,b){ console.log(a+b); }, b = { c:5, d:3 }; a.call(b,1,2); a.apply(b,[1,2]); a.cal ...
- 新增tab页无法获取到数据,原来是URL的rewrite配置文件忘了修改
昨天怎么也不明白为什么就是不能短网址访问,而且更迷惑的是居然数据也获取不到. 今天早上在网上搜ThinkPHP,想学习下这个框架.虽然知道是MVC模式,但是URL数据传递到底有什么阀门是我尚未了解到的 ...
- HDU 1025 Constructing Roads In JGShining's Kingdom(DP+二分)
点我看题目 题意 :两条平行线上分别有两种城市的生存,一条线上是贫穷城市,他们每一座城市都刚好只缺乏一种物资,而另一条线上是富有城市,他们每一座城市刚好只富有一种物资,所以要从富有城市出口到贫穷城市, ...
- ANDROID_MARS学习笔记_S02_004_ExpandableListActivity
1.main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...