IO输入与输出 下
字符编码
计算机里只有数字,计算机里的一切都是用数字来表示的,屏幕上显示的一个个字符也不例外
字符a对应的数字是97,字符b对用98,这种字符与数字对应的编码规则被称为ASCII。
中国大陆将每一个中文字符都用两个字节来表示,中文字符的每个字节的最高bit都为1,中国大陆为每个中文字符制定的编码规则称为GB2312
在中国大陆使用的计算机系统上,GBK和GB2312就被称为该系统的本地字符集
“中国”的“中”字,在中国大陆的编码是十六进制的D6D0,而在中国台湾的编码是十六进制的A4A4,台湾地区对中文字符集的编码规则称为BIG5
Unicode编码
ISO将全世界所有的符号进行了统一编码,称之为Unicode编码。
“中”这个符号,在全世界的任何角落始终对应的都是一个十六进制的数字4e2d。
Unicode编码的字符都占用两个字节的大小,对于ASCII码所表示的字符,只是简单地在ASCII码原来占用的一个字节前面,增加一个所有bits为0的字节。
Unicode 只占用两个字节,在全世界范围内所表示的字符个数不会超过2的16次方,实际上,Unicode编码中还保留了两千多个数值没有用于字符编码
在相当长的一段时间内,本地化字符编码将于Unicode编码共存。
java中的字符使用的都是Unicode编码,java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。
UTF-8编码
ASCII 码字符保持原样,仍然只占用一个字节,对于其它国家的字符,UTF-8使用的两个或三个字节来表示。使用UTF-8编码的文件,通常都要用EF BB BF作为文件开头的三个字节数据
UTF-16编码
UTF-16编码在Unicode基础上进行了一些细节上的扩充,增加了对Unicode编码没有包括的那些字符的表示方式
UTF-16对Unicode的扩充并没有影响Unicode编码所包括的那些字符,只是增加了对Unicode编码没有包括的那些字符的表示方式,一个使用Unicode编码的字符就是UTF-16格式的。
字符编码的操作体验
查看中文字符的GB2312码
查看中文字符的UTF-8码
查看中文字符的Unicode码
在Windows记事本程序中用不同的编码格式存储文本文件
字符编码应用的一个奇怪现象
用Windows记事本程序创建三个文件,其中分别输入“联通”、“联想"、"联",然后打开这三个文件,内容为”联通“和”联“的文件显示异常。
用UtraIEdit查看”联通联想“的GB2312码
字符编码的编程体验
打印中文字符的Unicode码
打印中文字符的GB2312码
验证写入到屏幕输出流的中文字符所采用的编码
查看系统的缺省编码
修改系统的缺省编码
验证从键盘输入流中读取的中文字符所采用的编码
研究GB2312码到unicode码的解码过程。
GB2312码的中文字符被按照ISO8859-1字符集解码生成了Unicode字符串后,如何将这个字符串转换成正确Unicode编码字符串
public class CharCode{
public static void main(String[] args){
String strChina="中国";
for(int i=0;i<strChina.length();i++)
{
System .out.println(Integer.toHexString(int)strChina.charAt(i));//取出每一个字符的unicode码
}
byte[] buf=strChina.getBytes("gb2312");
for(int i=0;i<buf.length;i++)
{
System.out.println(nteger.toHexString());
}
for(int i=0;i<buf.length;i++)
{
System.out.write(buf[i]);
}
}
}
过滤流与包装类
包装类的感念与作用
BufferedInputStream 与BufferedOuputStream类
DataInputStream 与DataOuputStream类
PrintStream类
ObjectInputStream 与ObjectOutputStream类
字节流于字符流的转换
包装类的概念与作用
DataOutputStream并没有对应到任何具体的流设备,一定要给它传递一个对应具体流设备的输出流对象,完成类似DataOutputStream功能的类就是一个包装类,也叫过滤流类或处理流类。
DataOutputStrea包装类的构造函数语法:
public DataOupputStream(OutStream out)
BufferedInputStream 与BufferedOuputStream类
缓冲流为I/O流增加了内存缓冲区,增加缓冲区有两个基本目的:
允许java程序一次不只操作一个字节,这样提高了程序的功能。
由于有了缓冲区,使得在流上执行skip,mark和reset方法都成为可能。
BufferedInputStream 与BufferedOuputStream是java提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中创建缓冲区。想想这种缓冲区与底层系统提供的缓冲区的区别。
BufferedInputStream的两个构造函数
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
BufferedOutputStream的两个构造函数
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int size)
BuffereReader和BufferedWriter类
BufferedReader的readLine方法可以一次读取一行文本,BufferedWriter的newLine方法可以向字符流中写入不同操作系统下的换行符。
DataInputStream与DataOuputStream类
public class DataStreamTest{
public static void main(String[] args){
FileOutputStream fos=new FileOutputStream("count.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
DataOutputStream dos=new DataOutputStream(bos);
dos.writeUTF("ab中国");
dos.writeBytes"ab中国");
dos.writeBchars("ab中国");
dos.close();
ileInputStream fis=new FileInputStream("count.txt");
BufferedInputStream bis=new BufferedInputStream(fos);
DataInputStream dis=new DataInputStream(bos);
System.out.println(dos.writeUTF());
byte[] buf=new byte[1024];
int len=dis.read(buf);
System.out.println(new String(buf,0,len));
fis.close();
}
}
PrintStream 类
PrintStream类提供了一系列的print和println方法,可以将基本数据类型的数据格式化成字符串输出。
PrintStream的3个构造函数:
PrintStream(OutputStream out)
PrintStream(OutputStream out,boolean atuoflush)
printStream(OutputStream out,boolean atuoflush,String encoding)
ObjectInputStream与ObjectOutputStream类
ObjectInputStream和ObjectOutputStream这两个包装类,用于从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。
对象中的transient和static类型的成员变量不会被读取和写入。
编程举例:创建一个可序列化的学生对象,并用ObjectOuputStream类把它存储到一个文件(mytext.text)中,然后再用ObjectInputStream类存储的数据读取到一个学生对象中,即恢复保存的学生对象。
import java.io.Serializable;
class Student implements Serializable{
in id;
String name;
int age;
String department;
public Student(int id,String name,int age,String department)
{
this.id=id;
this.name=name;
this.age=age;
}
}
import java.jo.*;
public class Serialization{
public static void main(String[] args){
Student stu1=new Student(19,"zhangsan",25,"huxue");
Student stu1=new Student(20,"lisi",23,"wuli");
FileOutputStream fos=new FileOutputStream("student.txt");
ObjectOutputStream os=new Object ObjectOutputStream();
os.writeObject(stu1);
os.writeObject(stu2);
so.close();
FileInputStream fis=new FileInputStream("student.txt");
ObjectInputStream ois=new Object ObjectInputStream();
stu1=(Student)os.readObject();
stu2=(Student)os.readObject();
ois.close();
System.out.println("id:"+stu1.id);
System.out.println("name:"+stu1.name);
System.out.println("age:"+stu1.age);
System.out.println("department:"+stu1.department);
System.out.println("id:"+stu2.id);
System.out.println("name:"+stu2.name);
System.out.println("age:"+stu2.age);
System.out.println("department:"+stu2.department);
}
}
字节流与字符流的转换
能不能找到一种简单的方式来读取键盘上输入的一行字符,如何找?
InputStreamReader 和 OutputStreamWriter,是用于将字节流转换成字符流来读写的两个类,InputStreamReader,是用于将字节流转换成字符流来读写的两个类,InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成字节后写入到一个字节流中。
InputStreamReader的两个主要构造函数
InputStreamReader(IputStream in)
InputStreamReader(InputStream in ,String CharsetName)
OutputStreamWriter的两个主要构造函数
OutputStreamWriter(OutputStream in)
OutputStreamWriter(OutputStream in,String CharsetName)
避免频繁的在字符中与字节间进行转换。
java程序与其他进程的数据通信
在java程序中可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。
调用Process类的getOutputStream和getInputStream方法可以获得连接到子进程的输出流和输入流对象
字符输入流类
Decorator 设计模式
在程序中用一个对象包装另外一个对象,这是一种被称为Decorator 的设计模式
如果要设计自己的IO包装类,这个类需要继承以Filterxxx命名的类,例如,
设计一对输入输出包装类:RecordInputStream和RecordOutputStream,来完成从数据库文件中读取记录和往数据库中写入记录。
import java.io.*;
public class TestPrintWriter{
public static void main(String[] args){
try{
throw new Exception("test");
}
catch(Exception e)
{
StringWriter sw=new StringWriter();
PrintWriter pw=new PrintWriter(sw);
e.printStackTrace( pw);
System.out.println(e.getMessage());
}
思考实践