IO流
作用:
利用Java语言中的IO流技术处理设备上的数据(硬盘上的文件,内存中驻留的数据)
分类:
按流向
- - - - 输入流
- - - - 输出流
按数据
- - - - 字节流
- - - - 字符流
抽象基类:
字符流
- - - - Reader
- - - - Writer
字节流
- - - - InputStream
- - - - OutputStream
功能性流对象
打印流
该流提供了打印方法,可以将各种数据类型的数据原样打印
字节打印流 PrintStream:
构造函数可以接收
- - - - File对象 File
- - - - 字符串路径 String
- - - - 字节输出流 OutputStream
字符打印流 PrintWriter:
构造函数可以接收
- - - - File对象 File
- - - - 字符串路径 String
- - - - 字节输出流 OutputStream
- - - - 字符输出流 Writer
public class PrintStreamDemo {
public static void main(String[] args) throws IOException{
BufferedReader bufr =
new BufferedReader(
new InputStreamReader(
System.in));
//基础形式
//PrintWriter out = new PrintWriter(System.out);
//true参数表示如果是流,在输入回车后自动flush
PrintWriter out = new PrintWriter(System.out, true);
//输出到文件中,但是没有true参数,true参数配合流使用
//PrintWriter out = new PrintWriter("a.txt");
//将文件封装到流中,就可以配合true参数使用
//true参数只针对于流使用,PrintWriter(“a.txt”, true)非法
//PrintWriter out = new PrintWriter(new FileWriter("a.txt"), true);
String line = null;
while((line = bufr.readLine()) != null){
if("over".equals(line))
break;
out.println(line.toUpperCase());
}
out.close();
bufr.close();
}
}
序列流
将多个流合并成一个流 SequenceInputStream
public class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("d:\\test\\1.txt"));
v.add(new FileInputStream("d:\\test\\2.txt"));
v.add(new FileInputStream("d:\\test\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("d:\\test\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1){
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
}
文件切割
public class SplitFile {
public static void main(String[] args) throws IOException{
splitFile();
merge();
}
public static void merge() throws IOException{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
al.add(new FileInputStream("d:\\test\\1.part"));
al.add(new FileInputStream("d:\\test\\2.part"));
al.add(new FileInputStream("d:\\test\\3.part"));
al.add(new FileInputStream("d:\\test\\4.part"));
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
public boolean hasMoreElements(){
return it.hasNext();
}
public FileInputStream nextElement(){
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("d:\\test\\splitFile.mp3");
byte[] buf = new byte[1024 * 1024];
int len = 0;
while((len = sis.read(buf)) != -1){
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
public static void splitFile() throws IOException{
FileInputStream fis = new FileInputStream("d:\\test\\sq.mp3");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len = fis.read(buf)) != -1){
fos = new FileOutputStream("d:\\test\\" + (count++) + ".part");
fos.write(buf, 0, len);
fos.close();
}
fis.close();
}
}
对象的序列化
直接操作对象的流,将堆内存中的对象通过此类存入硬盘中(对象的持久化)
被操作对象需要实现Serializable接口(标记接口)
ObjectInputStream
ObjectOutputStream
当被序列化类被修改时,Java自动生成的UID改变,以序列化的该类对象是无法使用该类的,需自定义静态值serialVersionUID
静态变量是不能被序列化的
如果非静态的变量也不想被序列化则定义transient关键字
public class Person implements Serializable{
//自定义UID值,在类被修改时保证在未被修改之前生成类的对象也能够使用该类
private static final long serialVersionUID = 100L;
private int id;
private String name;
//添加transient关键字,使非静态的参数不被序列化
transient int age;
//静态变量不会被序列化
static String country = "cn";
Person(int id, String name, int age, String country){
this.id = id;
this.name = name;
this.age = age;
this.country = country;
}
public String toString(){
return id + "::" + name + "::" + age + "::" + country;
}
}
public class TestObjectStream {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj() throws Exception{
ObjectInputStream ois =
new ObjectInputStream(
new FileInputStream("d:\\test\\Person.object"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj()throws IOException{
ObjectOutputStream oos =
new ObjectOutputStream(
new FileOutputStream("d:\\test\\Person.object"));
oos.writeObject(new Person(001, "zhangsan", 27, "US"));
oos.close();
}
}
**输出结果为:**1::zhangsan::0::cn
管道流
输入输出可以直接进行连接,通过结合线程使用
PipedInputStream
PipedOutputStream
public 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[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf, 0, len);
System.out.println(s);
in.close();
}catch(IOException e){
throw new RuntimeException("管道输入流失败");
}
}
}
class Write implements Runnable{
private PipedOutputStream out;
Write(PipedOutputStream out){
this.out = out;
}
public void run() {
try{
out.write("PipedStream is coming~".getBytes());
out.close();
}catch(Exception e){
throw new RuntimeException("管道输出流失败~");
}
}
}
RandomAccessFile
该类配合多线程可以实现数据的分段写入
该类不算IO体系中的子类,直接继承Object类
但是是IO包中的成员,可以通过指针对数据的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置,完成读写的原理就是内部封装了字节数入流和输出流
该类只能操作文件,且该操作文件还有模式:只读“r”、读写“rw”等
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException{
writeFile();
writeFile2();
readFile();
}
public static void readFile() throws IOException{
RandomAccessFile raf = new RandomAccessFile("d:\\test\\4.txt", "r");
//指针索引指向第八位
raf.seek(8);
//指针索引向右移动八位
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String s = new String(buf);
int age = raf.readInt();
System.out.println("name:" + s);
System.out.println("age:" + age);
raf.close();
}
public static void writeFile2() throws IOException{
RandomAccessFile raf = new RandomAccessFile("d:\\test\\4.txt", "rw");
//指针索引向右移动八位三次
raf.seek(8*3);
//此时指针在第四个八位,写入数据
raf.write("周七".getBytes());
raf.writeInt(103);
raf.close();
}
public static void writeFile() throws IOException{
RandomAccessFile raf = new RandomAccessFile("d:\\test\\4.txt", "rw");
raf.write("张三".getBytes());
//写入一个数值用四个字节保存
raf.writeInt(97);
}
}
操作基本数据类型的流对象DataStream
DataInputStream
DataOutputStream
public class DataStreamDemo {
public static void main(String[] args) throws IOException{
writeData();
readData();
writeUTF();
//自定义编码类型写入数据
OutputStreamWriter ows =
new OutputStreamWriter(
new FileOutputStream("d:\\test\\utf.txt"), "utf-8");
ows.write("你好");
ows.close();
readUTF();
}
public static void readUTF() throws IOException{
DataInputStream dis =
new DataInputStream(
new FileInputStream("d:\\test\\utfData.txt"));
String str = dis.readUTF();
System.out.println(str);
}
public static void writeUTF() throws IOException{
DataOutputStream dos =
new DataOutputStream(
new FileOutputStream("d:\\test\\utfData.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readData() throws IOException{
DataInputStream dis =
new DataInputStream(
new FileInputStream("d:\\test\\data.txt"));
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("d:\\test\\data.txt"));
dos.writeInt(123);
dos.writeBoolean(true);
dos.writeDouble(241.231);
dos.close();
}
}
用于操作字节数组的流对象ByteArrayStream
在构造的时候需要接收一个数据源,且数据源是一个字节数组
ByteArrayOutputStream在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组
这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭
public class TestByteArrayDemo{
public static void main(String[] args) throws IOException{
ByteArrayInputStream bis =
new ByteArrayInputStream("abcdefg".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch = bis.read()) != -1){
bos.write(ch);
}
System.out.println(bos.size());
System.out.println(bos.toString());
//只有writeTO方法需要抛出异常
bos.writeTo(new FileOutputStream("d:\\test\\byteArrayDemo.txt"));
}
}
转换流的字符编码、字符编码、字符编码-联通
编码:字符串转换成字节数组
解码:字节数组转换成字符串
public class TransCharactorTest {
public static void main(String[] args) throws IOException{
String s = "你好";
//用GBK进行编码
byte[] b1 = s.getBytes("GBK");
//数组转换成字符串
//System.out.println(Arrays.toString(b1));
String s1 = new String(b1, "ISO8859-1");
//用错误的解码格式进行编码,再用正确的格式进行解码
String s2 = new String(s1.getBytes("iso8859-1"), "GBK");
System.out.println("s2::" + s2);
}
}
练习
需求
有五个学生,每个学生有三门课程
从键盘输入以上数据(姓名,课程1, 2, 3)
计算出中成绩并把学生的信息和计算出的分数有高到低存放在文件“stud.txt”中
public class Test {
public static void main(String[] args) throws IOException{
Comparator<Student> cmp = Collections.reverseOrder();
Set<Student> set = StudentInfoTool.getStudents(cmp);
StudentInfoTool.writeToFile(set);
}
}
class StudentInfoTool{
public static Set<Student> getStudents() throws IOException{
return getStudents(null);
}
public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException{
BufferedReader bufr =
new BufferedReader(
new InputStreamReader(System.in));
String line = null;
Set<Student> stus = null;
if(cmp == null)
stus = new TreeSet<Student>();
else
stus = new TreeSet<Student>(cmp);
while((line = bufr.readLine()) != null){
if("over".equals(line))
break;
String[] info = line.split(",");
Student stu = new Student(info[0],
Integer.parseInt(info[1]),
Integer.parseInt(info[2]),
Integer.parseInt(info[3]));
stus.add(stu);
}
bufr.close();
return stus;
}
public static void writeToFile(Set<Student> stus) throws IOException{
BufferedWriter bufw =
new BufferedWriter(
new FileWriter("d:\\test\\stud.txt"));
for(Student stu: stus){
bufw.write(stu.toString() + "\t");
bufw.write(stu.getSum() + "");
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
class Student implements Comparable<Student>{
private String name;
private int ch, ma, en;
private int sum;
Student(String name, int ch, int ma, int en){
this.name = name;
this.ch = ch;
this.ma = ma;
this.en = en;
sum = ch + ma + en;
}
public String getName(){
return name;
}
public int getSum(){
return sum;
}
public int hashCode(){
return name.hashCode() + sum * 78;
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){
throw new ClassCastException("类型不匹配");
}
Student s = (Student)obj;
return this.name.equals(s.name) && this.sum == sum;
}
public String toString(){
return "student[" + name + "," + ch + "," + ma + "," + en +"]";
}
return int compareTo(Student s) {
int num = new Integer(this.sum).compareTo(new Integer(s.sum));
if(num == 0)
return this.name.compareTo(s.name);
return num;
}
}