IO流(Object)
构造方法摘要
ObjectInputStream(InputStream in)
创建从指定 InputStream 读取的 ObjectInputStream。
操作对象
ObjectInputStream 与 ObjectOutputStream
被操作的对象需要实现 Serializable (标记接口);
ObjectInputStream
Object
readObject()
从 ObjectInputStream 读取对象。ObjectOutputStream
void
writeObject(Object obj)
将指定的对象写入 ObjectOutputStream。
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
class Person implements Serializable{
public static final long serialVersionUID = 42L;
private String name;
private transient int age;
public static String contry ="cn";
Person(String name,int age,String contry){
this.name=name;
this.age=age;
this.contry = contry;
}
public String toString(){
return name+":"+age+":"contry;
}
}
public class Test{
public static void main(String...args) throws Exception{
writeObj();
readObj();
}
public static void readObj() throws Exception{
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("C:\\1.Java"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj() throws IOException{
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("C:\\1.Java"));
oos.writeObject(new Person("黑马程序员——新长城",20,"HK"));
oos.close();
}
}
注意三点:
1)静态是不能被序列化的。
2)如果非静态想被序列化可以加transient。
3)想被序列化的对象要实现Serializable。
IO流(管道流)
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
import java.io.PipedInputStream ;
import java.io.PipedOutputStream;
import java.io.IOException;
class Read implements Runnable{
private PipedInputStream in;
Read(PipedInputStream in){
this.in=in;
}
public void run(){
try{
byte[] buf =new byte[1024];
System.out.println("读取前。。没有数据阻塞");
int len = in.read(buf);
System.out.println("读到数据。。阻塞结束");
String data =new String(buf,0,len);
System.out.println(data);
in.close();
}
catch (Exception e){
throw new RuntimeException("管道输入失败");
}
}
}
class Write implements Runnable{
private PipedOutputStream out;
Write(PipedOutputStream out){
this.out=out;
}
public void run(){
try{
System.out.println("开始写入数据,等待六秒");
Thread.sleep(6000);
out.write("哥们来了".getBytes());
out.close();
}
catch (Exception e){
throw new RuntimeException("管道输出失败");
}
}
}
public class Test{
public static void main(String...args)throws IOException{
PipedInputStream pis =new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos);
Read r = new Read(pis);
Write w = new Write(pos);
new Thread(r).start();
new Thread(w).start();
}
IO流(RandomAccessFile)}
/*
RandomAccessFile 该类不是算是IO体系中子类。而是直接继承自Object。
但是它是IO包中成员。因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。
*/
构造方法摘要 RandomAccessFile(File file,String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由File
参数指定。
import java.io.IOException;
import java.io.RandomAccessFile;
public class Test{
public static void main(String...args)throws IOException{
writeFile();
//readFile();
}
public static void readFile()throws IOException{
RandomAccessFile raf =new RandomAccessFile("C:\\1.Java","r");
byte[] buf =new byte[20];
raf.seek(24*1);
int len = raf.read(buf);
String name =new String(buf);
int age = raf.readInt();
System.out.println("name = "+name+"\nage = "+age);
raf.close();
}
public static void writeFile()throws IOException{
}}RandomAccessFile raf =new RandomAccessFile("C:\\1.Java","rw");
raf.write("黑马程序员——新长城".getBytes());
raf.writeInt(97);
raf.write("黑马程序员——好男孩".getBytes());
raf.writeInt(99);
raf.write("黑马程序员——坏小孩".getBytes());
raf.writeInt(98);
raf.close();
此类还可以把数据分成一部分一部分,然后再把数据拼凑起来,跟我们下载程序是一样的,多线程。
(IO流基本数据操作流)
DataInputStream与DataOutputStream。
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.OutputStreamWriter;
public class Test{
public static void main(String...args)throws IOException{
//writeData();
//readData();
//writeUTF();
//readUTF();
//defaultGBK();
//utf_8();
}
public static void utf_8()throws IOException{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("C:\\UTF-8.Java"),"utf-8");
osw.write("你好");
osw.close();
}
public static void defaultGBK()throws IOException{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("C:\\GBK.Java"));
osw.write("你好");
osw.close();
}
public static void readUTF()throws IOException{
DataInputStream dis =
new DataInputStream(new FileInputStream("C:\\UTF.Java"));
String s = dis.readUTF();
System.out.println(s);
}
public static void writeUTF()throws IOException{
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("C:\\UTF.Java"));
dos.writeUTF("你好");
dos.close();
}
public static void readData()throws IOException{
DataInputStream dis =
new DataInputStream(new FileInputStream("C:\\data.Java"));
int i = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println(i+"..."+b+"..."+d);
dis.close();
}
public static void writeData()throws IOException{
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("C:\\data.Java"));
dos.writeInt(97);
dos.writeBoolean(true);
dos.writeDouble(12.56);
dos.close();
}
}
主要不同之处就是UTF修改版里面,俩个汉字是8个字节而,UTF-8俩个汉字是6个字节,GBK俩个汉字是4个字节。
(IO流字节数组操作流)
/*
用于操作字节数组的流对象。
ByteArrayInputStream : 在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭。
在流操作规律讲解时:
源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。
用流的读写思想来操作数组。
除了writeTo方法抛异常外,其他方法不会抛任何IOException
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
public class Test {
public static void main(String... args)throws IOException{
FileInputStream fis =new FileInputStream("1.Java");
int len =0;
byte[]buf =new byte[fis.available()];
len = fis.read(buf);
ByteArrayInputStream bis =
new ByteArrayInputStream(new String(buf,0,len).getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for(int by = 0;(by=bis.read())!=-1;){
bos.write(by);
}
System.out.println(bos.size());
System.out.println(bos.toString());
bos.writeTo(new FileOutputStream("C:\\2.Java"));
}
}
(IO流字符数组操作流)
CharArrayReader与CharArrayWriter跟字节数组操作流一样。
不需要调用底层资源(也就是文件),不会抛异常,除了writeTo方法外。
(IO流字符串操作流)
StringReader与StringWriter跟字节数组操作流一样。
不需要调用底层资源(也就是文件),不会抛异常。
(IO流编码表)
编码表由来:
计算机只能识别二进制数据,早期由来是电信号。
为了方便应用计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
常见编码表:
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表用一个字节的8位表示。
GB2312:中国的中文编码表。用两个字节来表示。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。用两个字节来表示。
Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
......
(IO流转换流字符编码)
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class Test{
public static void main(String...args)throws IOException{
writeGBKText();
readGBKText();
writeUTFText();
readUTFText();
}
public static void readUTFText()throws IOException{
InputStreamReader isr =
new InputStreamReader(new FileInputStream("C:\\UTF-8.Java"),"UTF-8");
char[] buf =new char[10];
for(int len = 0;(len=isr.read(buf))!=-1;){
System.out.println(new String(buf,0,len));
}
isr.close();
}
public static void readGBKText()throws IOException{
InputStreamReader isr =
new InputStreamReader(new FileInputStream("C:\\GBK.Java"),"GBK");
char[] buf = new char[10];
for(int len = 0;(len=isr.read(buf))!=-1;){
System.out.println(new String(buf,0,len));
}
isr.close();
}
public static void writeGBKText()throws IOException{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("C:\\GBK.Java"),"GBK");
osw.write("你好");
osw.close();
}
public static void writeUTFText()throws IOException{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("C:\\UTF-8.Java"),"utf-8");
osw.write("你好");
osw.close();
}
}
(字符编码表-编码-解码)
/*
编码:字符串变成字节数组。String->>byte[]: str.getBytes();
解码:字节数组变成字符串。byte[]->>String: new String(byte[]);
*/
构造方法摘要
String(byte[] bytes,String charsetName)
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的String
。
byte[]
getBytes(String charsetName)
使用指定的字符集将此String
编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
import java.util.Arrays;
public class Test{
public static void main(String...args)throws Exception{
String s = "哈哈";
//编码
byte[]b1 = s.getBytes("Unicode");
System.out.println(Arrays.toString(b1));
//解码
String s1 = new String(b1,"ISO8859-1");
System.out.println(s1);
//编码
byte[]b2 = s1.getBytes("ISO8859-1");
System.out.println(Arrays.toString(b2));
//解码
String s2 =new String(b2,"Unicode");
System.out.println(s2);
}
}
注意:
ISO8859-1码表之所以能编码解码是因为ISO8859-1不涉及到汉字编码
而UTF-8编码表涉及到了汉字编码,所以导致了数据的错乱。
Tomcat服务器默认编码是ISO8859-1。
(编码表特殊之处)
public class Test{
public static void main(String...args) throws Exception{
String s ="联通";
byte[]buf = s.getBytes("GBK");
for(byte b :buf){
System.out.println(Integer.toBinaryString(b&255));
}
}
}
发现GBK联通的编码跟UFT-8的编码形式相同,于是记事本就去找UTF-8的编码表,导致了数据错乱,解决方法就是在联通前面加个文字就OK了,但是不能是Ascll值,因为UTF-8里面兼容了Ascll码表。
(IO流练习)
/*
有五个学生,每个学生有3门课的成绩,
从键盘输入以上数据(包括姓名,三门课成绩),
输入的格式:如:zhagnsan,30,40,60计算出总成绩,
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件指定文件中。
1,描述学生对象。
2,定义一个可操作学生对象的工具类。
思想:
1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
2,因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。
所以可以使用TreeSet。
3,将集合的信息写入到一个文件中。
*/
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Set;
import java.util.TreeSet;
import java.io.File;
import java.util.Comparator;
import java.util.Collections;
class Student implements Comparable<Student>{
private String name;
private int cn;
private int ma;
private int en;
private int sum;
Student(String name,int cn,int ma,int en){
this.name=name;
this.cn=cn;
this.ma=ma;
this.en=en;
sum = (cn+ma+en);
}
public int getSum(){
return sum;
}
public String getName(){
return name;
}
public int hashCode(){
return this.name.hashCode()+sum*20;
}
public boolean equals(Object obj){
if(!(obj instanceofStudent))
throw newClassCastException("类型不匹配");
Student stu = (Student)obj;
return this.name.equals(stu.name) &&this.sum ==stu.sum;
}
public int compareTo(Student stu){
int num =this.sum-stu.sum;
if(num==0)
return this.name.compareTo(stu.name);
return num;
}
publicString toString(){
return "student["+"姓名:"+name+"\t语文 "+cn+"\t数学 "+ma+"\t英语 "+en+"]\t";
}
}
class StudentInfoTool{
public static Set<Student> getStudents()throws IOException{
returngetStudents(null);
}
public static Set<Student> getStudents(Comparator<Student>cmp)throws IOException{
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
Set<Student> stus =null;
if(cmp ==null)
stus = new TreeSet<Student>();
else
stus =newTreeSet<Student>(cmp);
String line =null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
String []arr = line.split(" ");
Student stu =new Student(arr[0],Integer.parseInt(arr[1]),
Integer.parseInt(arr[2]),
Integer.parseInt(arr[3]));
stus.add(stu);
}
bufr.close();
return stus;
}
public static void writeToFile(Set<Student>stus,File file)throws IOException{
BufferedWriter bufw =newBufferedWriter(new FileWriter(file));
for(Student stu : stus){
bufw.write(stu.toString());
bufw.write("\t"+stu.getSum());
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
public classTest{
public static void main(String...args)throws IOException{
Comparator<Student> cmp =Collections.reverseOrder();
Set<Student> set = StudentInfoTool.getStudents(cmp);
StudentInfoTool.writeToFile(set,new File("C:\\stu.txt"));
}
}