Java学习09-IO类2


1.带有行号的缓冲区:
LineNumberReader lnr=new LineNumberReader();
获取行号:lnr.getLineNumber();
设置行号从几开始:lnr.setLineNumber(100);
LineNumberReader 步骤
1.创建一个字符写入流对象
FileReader fr=new FileReader ("a.txt");
2.将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
LineNumberReader lnfr=new LineNumberReader (fr);
3.读取流对象:该缓冲区提供了一个一次读取一行的方法。当返回null时表示,文件读到末尾
String line=null;
while((line=lnfr.readLine())!=null)
{
String s=line;
String linenum=lnfr.getLineNumber();
}
4.关闭

lnfr.close();
扩展:自写LineNumberReader类

public class MyLineBufferReader extends MyBufferedReader {

	public MyLineBufferReader(Reader r) {
		super(r);
		
	}
	
	private int LineNumber;

	public int getLineNumber() {
		return LineNumber;
	}

	public void setLineNumber(int lineNumber) {
		LineNumber = lineNumber;
	}
	
	public String myReadLine() throws IOException
	{
		LineNumber++;
		return super.myReadLine();
	}

}

2.字节流:

InputStream  OutputStream

需求,想要操作图片数据。这时就要用到字节流。字节流读写的是byte[]数组,字符流动读写的是char[]

复制一个图片.

import java.util.*;
import java.io.*;
public class CopyPic {
         public static void main(String[] args)throws IOException {
                   copyPic();
         }
         public static void sop(Object obj){
                   System.out.println(obj);
         }
         public static void copyPic()throws IOException{
                   FileInputStream fip = new FileInputStream("a.jpg");
                   FileOutputStream fop = new FileOutputStream("d.jpg");
                   byte[] by = new byte[1024];
                   int num;
                   long time1 =System.currentTimeMillis();
                   while ((num = fip.read(by)) != -1) {
                            fop.write(by,0,num);
                   }
                   fip.close();
                   fop.close();
                   long time2 =System.currentTimeMillis();
                   sop(time2-time1);
 
         }
}

利用BufferedInputStream 复制mp3

import java.io.*;
public class CopyMp3  {
         public static void main(String[] args)throws IOException {
                   copy();
         }
         public static void copy()throws IOException{
                   BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.mp3"));
                   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.mp3"));
                   byte[] by = new byte[1024];
                   int num = 0;
                   while ((num = bis.read(by))!=-1) {
                            bos.write(by);
                   }
                   bis.close();
                   bos.close();
         }
}


重写myRead()方法
import java.io.*;

class MyBufferedInputStream{
	private InputStream in;

	private byte[] buf = new byte[1024*4];
		
	private int pos = 0,count = 0;
	
	MyBufferedInputStream(InputStream in){
		this.in = in;
	}

	//一次读一个字节,从缓冲区(字节数组)获取。
	public int myRead()throws IOException{
		//通过in对象读取硬盘上数据,并存储buf中。
		if(count==0){
			count = in.read(buf);
			if(count<0)
				return -1;
			pos = 0;
			byte b = buf[pos];

			count--;
			pos++;
			return b&255;
			// &255防止误提升为-1
		}
		else if(count>0){
			byte b = buf[pos];

			count--;
			pos++;
			return b&0xff;
		}
		return -1;

	}
	public void myClose()throws IOException{
		in.close();
	}
}


/*
11111111-111111110000000000101001001010100101010010101001010
byte: -1  --->  int : -1;
00000000 00000000 00000000 11111111  255
11111111 11111111 11111111 11111111
11111111  -->提升了一个int类型 那不还是-1吗?是-1的原因是因为在8个1前面补的是1导致的。
那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
怎么补0呢?
 11111111 11111111 11111111 11111111                        
&00000000 00000000 00000000 11111111 
------------------------------------
 00000000 00000000 00000000 11111111 
0000-0001
1111-1110
000000001
1111-1111  -1
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
*/


3.转换流

读取转换流:InputStreamReader

写入转换流:OutputStreamReader

读取转换流:InputStreamReader 字节流通向字符流的桥梁

步骤

1.获取键盘录入对象

Inputstream in=System.in

2.将字节流对象转换成字符流对象,使用转换流InputStreamReader

InputStreamReader isr=new InputStreamReader(in);

3.提高效率使用字符流缓冲区 BufferedReader进行读取

BufferedReader bf=new BufferedReader(is);

String line=null;

while((line=bf.readLine())!=null)

{

    if("over".equals(line))

     break;

    sop(line);

}

bufr.close;

写入转换流:OutputStreamReader 字符流通向字节流的桥梁

步骤

1.获取输出对象

Outputstream out=System.out

2.将字符流对象转换成字节流对象,使用转换流OutputstreamWriter

OutputstreamWriter osw=new OutputstreamWriter(out);

3.提高效率使用字符流缓冲区 BufferedWriter进行写入

BufferedWriter bw=new BufferedWriter(osw);

String line=null;

while((line=bf.readLine())!=null)

{

    if("over".equals(line))

     break;

    bw.write(line);

    bufw.newLine();

}

bufr.close;


键盘的最常见写法。

  BufferedReader bufr =

    new BufferedReader(new InputStreamReader(System.in));

注:转换流可以指定编码格式

4.流操作基本规律:
两个明确:
1.明确源和目的
   源:输入流。InputStream字节流  Reader 字符流
   目的:输出流 OutPutStream 字节流  Writer 字符流
 2.操作的数据是否是纯文本
   是 就是字符流 如果设备是键盘 就将字节流转换为字符流
   不是 就是 字节流
3.当体系明确后,在明确要是用那个具体的对象
    通过设备来区分 
     源设备  内存 硬盘 键盘
     目的设备  内存  硬盘  控制台
4.是否需要提高效率  是 BufferedReader  BufferedInputStream
                   否 BuffreredWriter BufferedOutputStream
案例分析 :
1.将一个文本文件中的数据存储到另一个文件中,复制文件
  源: InputStream字节流  Reader 字符流
  是否是纯文本 是  Reader
   设备: 文件   操作文件的对象 就是FileReader
  是否需要高效 
  是  BufferedReader
   FileReader fr=new FileReader("a.txt");
   BufferedReader bufr=new BufferedReader(fr);
 目的   OutPutStream 字节流  Writer 字符流
 是否是纯文本 :是 Writer 
 设备: 文件 写入文件的对象 就是 FileWriter 
 是否需要高效  是   BufferedWriter
  FileWriter fw=new FileWriter("b.txt");
   BufferedWriter bufw=new BufferedWriter(fw);

2.将一个图片文件数据存储到另一个文件中,复制文件。
分析
源:
 是否是纯文本 : 不是  InputStream
 设备 文件 就是 FileInputStream
  是否高效 是
 BufferedInputStream
   FileInputStream isr=new FileInputStream("a.jpg");
 BufferedInputStream bufis=new BufferedInputStream(isr);
目的
  是否纯文本 :不是 OutPutStream
  设备:文件 FileOutPutStream
是否高效 是
 BufferedOutputStream
 FileOutPutStream osw=new FileOutPutStream("b.jpg");
    BufferedOutputStream bufos=new BufferedOutputStream(osw);
 
3.扩展 :想要吧录入的数据按照指定的编码表(utf-8)将数据存到文件中
   目的:OutPutStream 字节流  Writer 字符流
   是否是存文本:是  Writer
   设备 :文件 fileWriter
   默认编码表是 gbk
   编码标只有转换流可以指定。所以要使用的对象是写入转换流 OutputStreamWriter
   转换流需要接受一个自己输出流,操作字节输出流的是FileOutputStream
   OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("b.txt"),"utf-8");
  BufferedWriter bufw=new BufferedWriter (osw);
通常涉及到字符编码转换的时候,就需要用到转换流。

练习:记录异常日志(涉及Date类)
   

import java.io.*;
import java.util.*;
import java.text.*;
class  ExceptionInfo{
	public static void main(String[] args)throws IOException {
		try{
			int[] arr = new int[2];
			System.out.println(arr[3]);
		}
		catch (Exception e){
			try{
				Date d = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String s = sdf.format(d);
				// 用于输出指定格式的日期
				PrintStream ps = new PrintStream("exeception.log");
				// 打印流输出文本很方便
				ps.println(s);
				System.setOut(ps);
			}
			catch (IOException ex){
				throw new RuntimeException("日志文件创建失败");
			}
			e.printStackTrace(System.out);
		}
	}
}
练习二:保存系统信息
import java.util.*;
import java.io.*;
public class SystemInfo  {
         public static void main(String[] args) throws Exception {
                   Properties p = System.getProperties();
                   PrintStream ps = new PrintStream("systemInfo2.txt");
                   System.setOut(ps);
                   // p.list(ps);
                   Set set = p.keySet();
                   // Iterator<String> it = set.iterator();
                   for(Object obj:set){
                            String value = (String)p.get(obj);
                            sop(obj+"="+value);
                   }
         }
         public static void sop(Object obj){
                   System.out.println(obj);
         }
}


5.对象流

import java.io.*;
	
	class Person implements Serializable{
	
	// public static final long serialVersionUID = 42L;
     // 如果标识唯一标识码,则不会改变
	private String name;
	transient int age;
	// transient 标记不会记录进去
	static String country = "cn";
	Person(String name,int age,String country){
		this.name = name;
		this.age = age;
		this.country = country;
	}
	public String toString(){
		return name+":"+age+":"+country;
	}
}

public class ObjectStreamDemo {
	public static void main(String[] args) throws Exception {
		
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:\\object.txt"));
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\object.txt"));
		oos.writeObject(new Person("nuddles",34,"cn") );
	    Person p = (Person)ois.readObject();
	    sop(p);
	    oos.close();
	    ois.close();

	}
	public static void sop(Object obj){
		System.out.println(obj);
	}
	
}

6.合并流

import java.io.*;
import java.util.*;

public class SequenceDemo  {
	public static void main(String[] args) throws IOException{
		Vector<InputStream> vector = new Vector<InputStream>();
		// Vector是一种枚举
		vector.add(new FileInputStream("d:\\1.txt"));
		vector.add(new FileInputStream("d:\\2.txt"));
		vector.add(new FileInputStream("d:\\3.txt"));
		vector.add(new FileInputStream("d:\\4.txt"));
		FileOutputStream out = new FileOutputStream("d:\\haha.txt");
		marge(vector,out);
	}
	public static void marge(Vector<InputStream> vector,OutputStream out) throws IOException{
		SequenceInputStream sis = new SequenceInputStream(vector.elements());
		byte[] by = new byte[1024];
		int len =0;
		while ((len=sis.read(by))!=-1) {
			
			out.write(by,0,len);
			out.flush();
		}
		sis.close();
		out.close();

	}
}

7.RandomAccessFile

该类不是算是IO体系中子类。

而是直接继承自Object。

但是它是IO包中成员。因为它具备读和写功能。

内部封装了一个数组,而且通过指针对数组的元素进行操作。

可以通过getFilePointer获取指针位置,

同时可以通过seek改变指针的位置。

其实完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件。

而且操作文件还有模式:只读r,,读写rw等

如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。

如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

import java.io.*;
import java.util.*;
public class RandomAccessFileDemo  {
         public static void main(String[] args) throws IOException{
                   write();
         }
         public static void sop(Object obj){
                   System.out.println(obj);
         }
         public static void write() throws IOException{
                   RandomAccessFile raf = new RandomAccessFile("d:\\nuddles.txt","rw");
                   raf.write("this is my file".getBytes());
                   raf.skipBytes(8);
                   raf.writeInt(56);
                   raf.seek(0);
                   // 读之前要跳回到0指针处
                   byte[] by = new byte[1024];
                   raf.read(by);
                   String s = new String(by);
                   sop(s);
                   raf.close();
         }
}

8.DataInputStream与DataOutputStream

可以用于操作基本数据类型的数据的流对象。

有相应读写各种类型的方法,特殊方法:readUTF/writeUTF


9.用于操作字节数组的流对象。

ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。

ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。

这就是数据目的地。

因为这两个流对象都操作的数组,并没有使用系统资源。

所以,不用进行close关闭。

在流操作规律讲解时:

源设备,

 键盘 System.in,硬盘 FileStream,内存 ArrayStream。

目的设备:

 控制台 System.out,硬盘FileStream,内存 ArrayStream。

用流的读写思想来操作数据。

import java.io.*;
class ByteArrayStream
{
         public static void main(String[] args)
         {
                   //数据源。
                   ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());
 
                   //数据目的
                   ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
                   int by = 0;
 
                   while((by=bis.read())!=-1)
                   {
                            bos.write(by);
                   }
 
                   System.out.println(bos.size());
                   System.out.println(bos.toString());
}




  


































  
  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值