----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
字节流:
需求:想要操作图片数据。这时就要用到字节流基类:InputputStream OutputStram
类名中带有stream的流都是字节流
底层有缓冲区
一:比较字符流与字节流中的write方法
字符流中:FileWriter fw=new FileWriter("demo.txt");
fw.write("abcde");
fw.flush();
//经过这三步才能将要写的数据写到目的地
字节流中:FileOutputStream fos=new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());
//有这两步就可以,无需刷新
二:字节流的两种读方法
1.读一个写一个,边读边写
public static void readFile_1() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
int ch=0;
while((ch=fis.read())!=-1)
{
System.out.print((char)ch);
}
fis.close();
}
2.先读到字节数组中,再写
public static void readFile_2() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
byte [] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1)
{
System.out.print(new String(buf,0,len));
}
}
3.int num=fis.available(); //available方法放回文件中的字符个数
byte [] buf=new byte[fis.available()];
fis.read(buf);
//定义一个刚好合适的缓冲区,不用再循环了。
这种方法虽然方便快捷,但有危险,数组的容量不能太大了,否则,内存很有可能因为
溢出,受不了而废掉。它只适用于操作数据较小的文件。
三:复制一个图片
思路:
1.用字节读取流对象和图片关联。
2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3.通过循环读写,完成数据的存储
4.关闭资源
eg:FileOutputStream fos=null;
FileInputStream fis=null;
try
{
fos=new FileOutputStream("复制的图片.bmp");
fis=new FileInputStream("..\\media\\84.bmp");
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{}
四:通过缓冲区复制一首MP3歌曲
eg:public static void main(String[] args) throws IOException
{
long start=System.currentTimeMillis();
copy_1();
long end=System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("..\\media\\
刘若英 - 当爱在靠近.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("复制的歌.mp3"));
int by=0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
五:通过自制的缓冲区来复制一首歌
eg:public static void copy_2() throws IOException
{
MyBufferedInputStream bufis=new MyBufferedInputStream(new FileInputStream ("..\\media\\刘若英 - 当爱在靠近.mp3"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("复制的 歌.mp3"));
int by=0;
System.out.println("第一个字节:"+bufis.myRead());
while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
class MyBufferedInputStream
{
private InputStream in;
private byte [] buf=new byte[1024];
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; //注意:该处的b为用二进制格式存储歌曲数据的字节数组
}
else if(count>0)
{
byte b=buf[pos];
count--;
pos++;
return b&0xff; //此处的b和原来一样
}
return -1;
}
public void myClose() throws IOException
{
in.close();
}
}
六:注:五中的b从二进制变为int形式时有一个小技巧:
b返回时为二进制,默认为8位,int型占四个字节,java中二进制表示为32位
由返回的二进制b值转化为int型,系统默认b不足32位时,在它前面补1;即转化为int
型后,返回的值变成了负数,而
while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
不满足循环的条件,即一开始就不能写任何数据到指定的目的地,也就是一点内容都没有
复制,所以运行后生成的文件为空文件。
要想使返回的二进制b值转化为int型时不改变其值,又让其变为十进制整数
方法是:保留n位,与2的n次方减1相与
eg:
byte:-1 ---》int :-1;
11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111
&00000000 00000000 00000000 11111111
-------------------------------------
00000000 00000000 00000000 11111111
为什么返回时要为int型呢? 原因是避免了返回-1及负数的情况,导致不满足写的条件,从而不能进行 写操作,将byte型转为int型后,字节数增大了,一个变为了四个,按道理write的目的地应增大4倍。但
write方法是只写有效的低字节位数据,即它一直在做强转的动作,将32位只保留低8位有效位的强转。
七:读取键盘录入
1.System.out:对应的是标准的输出设备:控制台
2.System.in:对应的标准输入设备:键盘
需求:
通过键盘录入数据
当录入一行数据后,就将改行数据进行打印
如果录入的数据时over,那么停止录入
eg:public static void main(String[] args) throws IOException
{
InputStream in=System.in;
StringBuilder sb=new StringBuilder();
while(true)
{
int ch=in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s=sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
//toUpperCase():使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
sb.delete(0,sb.length());
//清空该字符串缓冲区对象b中的数据,起到刷新的效果
}
else
{
sb.append((char)ch);
}
}
}
八:字节流转换为字符流的桥梁
1.InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。 它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启 用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节 2.为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。
eg: InputStream in=System.in;
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
3.七中的代码类似读一行数据的原理。也就是readLine方法
readLine方法是字符流bufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法
这就需要将字节流转换为字符流,再使用readLine方法
eg:
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象
1.InputStream in=System.in;
//将字节流对象转换为字符流对象。使用转换流:BufferedReader
2.InputStreamReader isr=new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区高效操作,使用BufferedReader
3.BufferedReader bufr=new BufferedReader(isr);
//键盘录入最常见的写法,System.in一次只能写一个字符,而上面的写法却能一次读入
一行字符,效率很高。
4.OutputStream out=System.out;
5.OutputStreamWriter osw=new OutputStreamWriter(out);
6.BufferedWriter bufw=new BufferedWriter(osw);
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
//System.out.println(line.toUpperCase());
7.bufw.write(line.toUpperCase());
8.bufw.newLine();
9.bufw.flush();
}
bufr.close();
}
}
输出底层用的就是流装置,可以用流来改写System.out.println();
上面的代码中的123和789六行代码就是用来改写它的。
其中:123句等价为:BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
456句等价为:BufferedWriter bufr=new BufferedWriter(new OutputStreamWriter(System.out));
九:字符流转换为字节流的桥梁
1.OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字 节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得 到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够 大。注意,传递给 write() 方法的字符没有缓冲。
2.为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中
eg: Writer out= new BufferedWriter(new OutputStreamWriter(System.out));
十:确定具体程序该使用字符流还是字节流的方法
流操作的基本规律:
通过两个明确来完成。
1.明确源和目的
源:输入流:InputStream Reader
目的:输出流:OutputStream Writer
2.明确操作的数据是否是纯文本
是:字符流
不是:字节流
3.当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台。
分情况:
情况一:想把键盘录入的数据存储打印到控制台
源:键盘
目的:控制台
情况二:想把键盘录入的数据存储到一个文件中
源:键盘
目的:文件
情况三:需求:想要将一个文件的数据打印到控制台上
源:文件
目的:控制台
十一:实例
1.将一个文本中的数据存储到另一个文件中,复制文件。
源:因为是源,所以使用读取流:InputStream Reader
是不是操作文本文件。
是!这是就可以选择Reader
这样体系就明确了
接下来明确要使用该体系中的那个对象。
明确设备:硬盘上一个文件。
Peader体系中可以操作文件的对象是FileReader
是否需要提高效率
是!.加入Readter体系中的缓冲区BufferedReader.
FileReader fr=new FileReader("a.txt");
BufferedReader bufr=new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件
Write体系中可以操作文件的对象FileWriter。
是否需要提高效率
是!.加入Readter体系中的缓冲区BufferedReader.
FileWriter fw=new FileWriter(b.txt);
BufferedWriter bufw=new BufferdWriter(fw);
------------------------------------------------------------------------------
2. 需求:将键盘录入的数据保存到一个文件中。
这个文件有源和目的都存在。
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘:对应的对象是System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文件数据方便。转成字符流按照字符串操作是最方便的
所以既然明确了Reader,那么就将System.in转换成Reader
用了Reader体系中转换流:InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr=new BufferedReader(isr);
目的:OutputStram Writer
是否是纯文本?是!writer
设备:硬盘。一个文件。使用FileWriter
FileWriter fw=new FileWriter(c.txt);
需要提高效率吗?需要
BufferedWriter bufw=new BufferedWriter(fw);
-----------------------------------------------------------------------------
扩展:想要把录入的数据按照指定的编码表,将数据存储到文件中
目的:OutputStram Writer
是否是纯文本?是!writer
设备:硬盘。一个文件。使用FileWriter
但是FileWriter是使用的默认编码表:GBK
但是存储时,需要加入指定的编码表,而指定的编码表只有转换流可以指定
所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节流,而且还可以操作文件的字节输出流,用FilOutputStream
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(d.txt),"UTF-8");
需要提高效率吗?需要
BufferedWriter bufw=new BufferedWriter(osw);
-----------------------------------------------------------------------------
记住:转换流什么时候实用,字符和字节之间的桥梁,通常涉及到字符编码转换时,
需要用到转换流
转换流的由来:就是因为它能指定编码,他能把字节转换过来加指定的码表。
十二:改变默认的输入源设备和输出目的设备
eg:
System.setIn(new FileInputStream("PersonDemo.java"));
//这一句改变的是输入源设备,改为文件
System.setOut(new PrintStream("zz.txt"));
//这一句改变的是输出流设备,改为文件
----------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------