第一讲. 对象流 ObjectInputStream, ObjectOutputStream
- 对象流可以把堆内存中的对象存储起来。首先要求对象本身implements Serializable接口,标示其可以序列化,否则会有NotSerializableException。
- Serializable 是一个标记接口,本身不要求其实现类为其实现任何方法。
- 静态成员无法序列化,即不会被存入硬盘中,因为它在方法区存储,而不在堆内存中
- 可以加入transient 关键字修饰类成员,令其不会被序列化
import java.io.*;
class ObjectIODemo
{
public static void main(String[] args) throws Exception
{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("object.txt"));
ObjectInputStream in = new ObjectInputStream(new FileInputStream("object.txt"));
out.writeObject(new Person("Lisi",20));
Person p = (Person)in.readObject();
System.out.println(p);
in.close();
out.close();
}
}
class Person //implements Serializable
/**
<span style="white-space:pre"> </span>序列号uid是通过类的成员计算得到的。也可以自己指定。
**/
{
private static final long serialVersionUID = 42L; //自定义uid
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "name="+name+";age="+age;
}
}
第二讲. 管道流PipedInputStream PipedOutputStream
- 管道流为多线程而设计的IO流,单线程会导致死锁,读写两个管道应异步进行。
- 可以对接,读写双发可以在创建时把对方当参数传入,也可以利用connect方法
import java.io.*;
class PipedStreamDemo
{
public static void main(String[] args) throws IOException
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
Read r= new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();
}
}
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in){this.in = in;}
public void run(){
try{
byte[] buff = new byte[1024];
int len = in.read(buff);
String s = new String(buff,0,len);
System.out.println(s);
in.close();
}
catch(IOException e){
throw new RuntimeException("Error in input Pipe!");
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out){this.out = out;}
public void run(){
try{
out.write("hahahaha!".getBytes());
out.close();
}
catch(IOException e){
throw new RuntimeException ("Error in output Pipe~");
}
}
}
第三讲.RandomAccessFile
- 工具类,直接继承自Object
- 里面封装了一个数组,通过指针对元素进行操作
- 在内部封装了字节输入和输出流
- 只能操作文件,而且有模式限制(只读"r",读写"rw"等)。rw对文件进行追加,若没有则创建。r不会创建文件。当然为了防止你写错,会抛异常。
- 可以实现多线程下载(通过指针指定文本的不同位置),即异步同时写入
import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
writeFile();
readFile();
}
private static void writeFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);//raf.write(97); // 只取最低8位
raf.write("王五".getBytes());
raf.writeInt(99);
raf.seek(8*3);
raf.write("周七".getBytes());
raf.writeInt(102);
raf.close();
}
private static void readFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
raf.seek(8); //raf.skipBytes(8);
byte[] buff = new byte[4];
raf.read(buff);
String name = new String(buff);
int age = raf.readInt();
System.out.println(name+age);
raf.close();
}
}
第四讲. DataInputStream, DataOutputStream 专门用来操作基本数据类型
- 数据流,可以用它处理各种基本类型数据
- writeUTF方法写入的数据只能用对应的readUTF读,它写入的格式跟一般utf格式是不一样的。
import java.io.*;
class DataStreamDemo
{
public static void main(String[] args) throws IOException
{
writeData();
readData();
}
private static void writeData() throws IOException
{
DataOutputStream out = new DataOutputStream (new FileOutputStream("data.txt"));
//out.writeInt(345);
out.writeUTF("你好");//只能用对应的readUTF读
out.close();
}
private static void readData() throws IOException
{
DataInputStream in = new DataInputStream (new FileInputStream ("data.txt"));
System.out.println(in.readUTF());
in.close();
}
}
第五讲. ByteArrayInputStream,ByteArrayOutputStream 不涉及底层资源操作,直接读写数组
- 用流的读写思想操作数组,同理也有CharArrayReader,CharArrayWriter;StringReader,StringWriter
- ByteArrayInputStream需指定一个字节数组作为数据源;ByteArrayOutputStream内部封装一个可变长度的字节数组,不用定义目的
- 没有IO异常,close方法无效(也没必要)
- ByteArrayOutputStream 有writeTo(OutputStream out) ,讲字节数组缓冲区中的数据写入到一个目的中(只有这个涉及底层操作)
import java.io.*;
class ByteArrayStreamDemo
{
public static void main(String[] args)
{
ByteArrayInputStream in = new ByteArrayInputStream ("ABCDEFG".getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
int by;
while((by=in.read())!=-1)
out.write(by);
System.out.println(out.toString());
}
}
第六讲. 字符编码
Ascii 码表 | 美国标准信息交换码 ,用一个字节的7位可以表示 |
ISO8859-1 | 拉丁码表、欧洲码表,用一个字节的8位表示,一些服务器会使用 |
GB2313 | 中国的中文编码表,两个字节表示。为了兼容英文码表,两个字节高位都是1(都是负数),6k~7k字 |
GBK | 中文编码表升级版,容纳更多的字,约20k字 |
Unicode | 国际标准编码表,融合多种文字,所有都两个字节表示 |
UTF-8:8-bit unicode transformation format | 最少用一个字节,最多用三个字节表示一个字符,为使其便于识别,每个字节前都加入特定码头,如下图: |
- “你好”的utf-8编码形式,被GBK解码得到“浣犲ソ”;“你好”GBK编码被utf-8解码得到“??”
- 像“联通”,它的编码是符合uft-8的编码头的,用记事本打开会按照utf-8解码
为 String.getBytes(String charSet) 方法指定字符集时会抛出UnsupportedEncodingException异常,防止不支持的字符集输入
/**
编码:字符串变字节数组 String str;str.getBytes(String charsetName);
解码:字节数组变字符串 new String(byte[],charsetName);
**/
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
String str1 = "你好";
byte[] b1 = str1.getBytes("uft-8"); //默认是GBK
//模拟服务器端应用欧洲码表的场景,此时需用重编解码的方式获得原中文文本
String str2 = new String(b1,"iso8859-1"));
byte[] b2 = str2.getBytes("ios8859-1"));
String str3 = new String(b2,"utf-8");
}
}
练习题
/** 练习:
1.有五个学生,每个学生有三门课的成绩
2.有键盘输入,格式如Lisi,45,48,87 , 计算总分
3.按总成绩大小顺序将学生信息输出到"stud.txt"文件中
**/
import java.io.*;
import java.util.*;
class Test
{
public static void main(String[] args) throws IOException
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Set<Student> students = new TreeSet<Student>();
String name;
int[] scores = new int[3];
for (int i=1;i<=5 ;i++ )
{
System.out.println("请输入第"+i+"名学生的信息:");
String line = in.readLine();
String[] strs = line.split(",");
name=strs[0].trim();
for (int j=2;j<=strs.length ;j++ )
scores[j-2]=Integer.parseInt(strs[j-1].trim());
students.add(new Student(name,scores));
}
in.close();
PrintStream out = new PrintStream("stud.txt");
out.println(students);
out.close();
}
}
class Student implements Comparable<Student>
{
private String name;
private int[] scores = new int[3];
private int score;
Student(String name,int[] scores)
{
this.name = name;
for (int i=0;i<scores.length ;i++ )
{
this.scores[i]=scores[i];
score+=scores[i];
}
}
public int compareTo(Student stu){
return stu.score-this.score;
}
public boolean equals(Object stu){
if (!(stu instanceof Student))
return false;
return this.name.equals(((Student)stu).name);
}
public String toString(){
StringBuilder str = new StringBuilder();
str.append(name+",");
for (int i=0;i<3 ;i++ )
{
str.append(scores[i]);
str.append(",");
}
str.append("总分:"+score+"\n");
return str.toString();
}
}