黑马程序员java学习日记十一 IO流

一、IO流的三种分类方式

1.按流的方向分为:输入流和输出流

2.按流的数据单位不同分为:字节流和字符流

3.按流的功能不同分为:节点流和处理流

二、IO流的四大抽象类:

字符流:Reader Writer

字节流:InputStream(读数据)

OutputStream(写数据)

三、缓冲流:缓冲流要套接在相应的节点流之上,提高了读写的效率。

此处理流的构造方法都得传相对应的基类类型

BufferedReader:提供了readLine方法用于高校读取一行字符串

BufferedWriter:提供了newLine用于写入一个行分隔符也就是换行

BufferedInputStream 没多大用处

BufferedOutputStream 没多大用处

四、转换流:主要作用将字节流转换成字符流。用处较大!

转换流在构造时可以指定其编码集合

InputStreamReader需要和InputStream套接

OutputStreamWriter需要和OutputStream套接

例:OutputStreamWriter osw = new OutputStreamWriter (new FileOutputStream(文件路径);

方法例:osw.getEncoding();获得流的编码方式

五、数据流与字节数组流:

数据流主要为实现可以存取Java原始数据类型如long,boolean

数据流是字节流

DataInputStream需要和InputStream套接

DataOutputStream需要和OutputStream套接

DataInputStream方法:readBoolean() readInt() read……()……

readUTF():网络传输常用方法读一个Unicode字符串

DataOutputStream方法与DataInputStream基本对应为写的方法

//此构造函数等于已可以往一个字节数组里输入内容

ByteArrayOutputStream baos = new ByteArrayOutputStream ();

//此方法为获取一个字节数组方法返回字节数组

baos.toByteArray();

//此方法获取字节数组占了多少字节

new ByteArrayInputStream(一个字节数组)。available()

1 ByteArrayOutputStream baos =
2 new ByteArrayOutputStream();
3 DataOutputStream dos =
4 new DataOutputStream(baos);
5 try {
6 dos.writeDouble(Math.random());
7 dos.writeBoolean(true);
8 ByteArrayInputStream bais =
9 new ByteArrayInputStream(baos.toByteArray());
10 System.out.println(bais.available());
11 DataInputStream dis = new DataInputStream(bais);
12 System.out.println(dis.readDouble());
13 System.out.println(dis.readBoolean());
14 dos.close(); dis.close();
15 } catch (IOException e) {
16 e.printStackTrace();
17 }

六、Print流

Print流只有输出流无输入流,PrintWriter和PrintStream分别针对字符字节

两个类提供了重载的Print和Println方法用于多种数据类型的输出

PrintWriter和PrintStream的输出操作不会抛出异常

PrintWriter和PrintStream有自动flush功能

----System.setOut(接收OutputStream类):用于设置系统默认输出流

   

 

   字符流的缓冲区
   缓冲区的出现提高了对数据的读写效率
   对应类:
   BufferedWriter
   BufferedReader
   缓冲区要结合流才能使
   BufferedWriter缓冲区提供了一个跨平台的换行符

   newLine()方法返回的时候只返回回车符之前的数据类容,并不返回回车符。

   创建一个字符写入流对象(FileWriter fw = new FileWriter("buf.txt");) 
   为了提高字符写入流的效率,加入缓冲技术,原理是对象里面封装了数组。
   只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
    BufferedWriter bufw = new BufferedWriter(fw);

    for(int x=1;x<5;x++)
    {
    bufw.write("abcd"+x);
    bufw.newLine();                            
    bufw.flush();                 //只要用到缓冲区,就要记得刷新
    }

     bufw.flush();

     bufw.close();              //缓冲区的关闭,关闭中包含刷新可简写刷新

     字符读取流缓冲区:

     该缓冲区提供了一次读一行的方法,readline()返回类型String
     包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

     //创建一个读取流对象,和文件相关联
     FileReader fr = new FileReader("buf.txt");

    //为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
    BufferedReader bufr = new BufferedReader(fr);

    //读一行的方法: String readLine() 返回类型String
    //包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

   String line = null;
   while((line=bufr.readLine())!=null)
   {
   System.out.println(line);
   }

   bufr.close();

通过缓冲区复制一个.java文件

public static void copy()
{
BufferedWriter bufw = null;
BufferedReader bufr = null;
try
{
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("Copy_BufferedWriterDemo.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
if(bufw!=null)
{
try
{
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
if(bufr!=null)
{
try
{
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
}

}
}

包含一个功能和readerLine一致的方法来模拟一个BufferedReader

class MyBufferedReader
{
private FileReader r;

MyBufferedReader(FileReader r)
{
this.r=r;
}
//可以一次读一行的方法
public String myReadLine() throws IOException
{
//定义一个临时容器,原BufferedReader封装的是字符数组
//为了演示方便,定义一个StringBuilder容器。因为最终是要将数据变成字符串
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void myClose() throws IOException
{
r.close();
}
}

BufferedReader(Reader in) 即传入的是Reader类型对象,所以我们也要传入Reader类型。由于Reader中
有很多抽象方法,所以,需要继承reader然后覆盖这些抽象方法。

class MyBufferedReader extends Reader
{
private Reader r;

MyBufferedReader(Reader r)
{
this.r=r;
}
//可以一次读一行的方法
public String myReadLine() throws IOException
{
//定义一个临时容器,原BufferedReader封装的是字符数组
//为了演示方便,定义一个StringBuilder容器。因为最终是要将数据变成字符串
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}


public int read(char[] cbuf, int off, int len)throws IOException
{
return r.read(cbuf,off,len);
}
public void close() throws IOException
{
r.close();
}

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

LineNumberReader

跟踪行号的缓冲字符输入流

继承了BufferedReader

LineNumberReader类中的readerLine覆盖了类 BufferedReader 中的 readLine

因为LineNumberReader中的ReaderLine方法中涉及到行号的输出。所以要覆盖父类BufferedReader中的readLine

方法

模拟自己的LineNumberReader中的readLine方法:

import java.io.*;
class MyLineNumberReader extends MyBufferReader
{
private Reader r;
private int LineNumber=0;

MyLineNumberReader(Reader r)
{
super(r);
}

public String myReaderLine() throws IOException
{
LineNumber++;
return super.myReadLine();
}

public void setLineNumber(int LineNumber)
{
this.LineNumber=LineNumber;
}
public int getLineNumber()
{
return LineNumber;
}
}


import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("d:\\2.jpg");
fis = new FileInputStream("d:\\1.jpg");
byte[] buf = new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
MP3的复制

import java.io.*;
class CopyMp3
{
public static void main(String[] args) throws IOException
{
long start = System.currentTimeMillis();
//Copy_1();
Copy_2();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}

//通过字节流的缓冲区完成复制。
public static void Copy_1() throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("d:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("d:\\1.mp3"));

int by=0;
while((by=bufis.read())!=-1)
{
bufos.write(by);//由于read方法把byte提升为int,而write在做一个强转,只写最低八位。
//保证了数据的准确性。
}
bufos.close();
bufis.close();
}
//使用自己定义的MyBufferedInputStream来拷贝mp3
public static void Copy_2() throws IOException
{
MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("d:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("d:\\1.mp3"));

int by=0;
//System.out.println("第一个字节是:"+bufis.myread());
while((by=bufis.myread())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myclose();
}
}
自定义BufferedInputStream

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)//即上一行装操作到最后,没有数据了,执行read后返回-1了,所以count<0
return -1;
pos=0;
byte b = buf[pos];
count--;
pos++;
return b&255;
}
else if(count>0)
{
byte b = buf[pos];
count--;
pos++;
return b&0xff;//255十六进制
}
return -1;
}
public void myclose() throws IOException
{
in.close();
}
}

在CopyMp3中使用自己的定义MyBufferedInputStream,导致复制的文件很小,损坏了文件。

总结:诸多的流操作却不知道选用哪个下面对次的规律总结;

流操作的基本规律:
    1.明确源和目的
     源:输入流:InputStream Reader
     目的:输出流 OutputStream Writer
   2.明确操作的数据是否是纯文本。
     是:字符流
     否:字节流

3.当体系明确后再明确要使用哪个具体的对象
     通过设备来进行区分。
     源设备:内存,硬盘,键盘
     目的设备:内存,硬盘,控制台

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值