Java IO流(字节流)

------- android培训java培训、期待与您交流! ----------

IO   字节流

字节流两个超类:InputStream  OutputStream(写)

一、

InputStream --->字节输入流 (读)

 

public abstract class InputStream 

extends Object

implements Closeable

此抽象类是表示字节输入流的所有类的超类。

需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。

OutputStream --->输出字节流(写)


public abstract class OutputStream

extends Object

implements CloseableFlushable

此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。


二、具体操作示例

1、补充:掌握类 FileInputStream 的available()方法
FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

 int

available()
          返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。

 

 

示例:
import java.io.*;
class  FileStream
{
public static void main(String[] args) throws IOException
{
readFile_3();
}
 
public static void readFile_3()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。数据量太大不好用
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
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.println(new String(buf,0,len));
}
fis.close();
}
public static void readFile_1()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}
fis.close();
}
public static void writeFile()throws IOException
{
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());
fos.close();
}
}
 
2、需求,想要操作图片数据,复制一个图片,这时就要用到字节流。
复制一个图片
思路:
1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。
示例:
import java.io.*;
class  CopyPic
{
public static void main(String[] args) 
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.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
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
 
3演示mp3的复制。通过缓冲区。
BufferedOutputStream
BufferedInputStream     
  fileinputstreamread()存在数组然后用bufferedinputstream 得 read ()在缓冲区一个一个往外取
(自定义字节流的缓冲区-readwrite的特点).
IO流自定义字节流的缓冲区:
思路:BufferedInputStream类中read()方法的工作原理
1)先一个一个从字节流中读取字节,读取一定量(自定义)之后,存储在一个字节数组(缓冲区)(FileInputStream.read(byte[] b)),并获得存储数量(read方法的返回值)。
2)一个一个字节返回,返回一个,存储数量减1,然后指针往后移一位,准备取下一个。
3)如果存储数量为,代表当前数组中所有数据已经全部取完,此时再来一次读取(read(byte[] b)),再获得此次存储数量。
4)如果存储数量(即read方法返回-1),代表读到文件末尾,返回-1
因此,需要用到以下几个变量:
读取的字节数量,指向数组中准备取哪一个的指针,将要返回的字节变量。
自定义的read方法实现如下:
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;
}
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的原因是因为在81前面补的是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来确定的。【 如果文件开头第一个字节就是1111 1111,则返回的直接就是-1(方法返回类型为int),这样就被当做是读到文件末尾而导致读取结束。因此要与上255,即(00000000 00000000 00000000 11111111),这样的话,才保证原字节值没变,而且不被当做-1而导致读取结束。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了240,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
复制MP3示例:
import java.io.*;
class  CopyMp3
{
public static void main(String[] args) throws IOException
{
long start = System.currentTimeMillis();
copy_2();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
public static void copy_2()throws IOException
{
MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\9.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\3.mp3"));
int by = 0;
//System.out.println("第一个字节:"+bufis.myRead());
 
while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
 
//通过字节流的缓冲区完成复制。
public static void copy_1()throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
 
4、读取键盘录入。【必要掌握】
System.out:对应的是标准输出设备,控制台。
System.in:对应的标准输入设备:键盘。
需求:
通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么停止录入。
 
import java.io.*;
class  ReadIn
{
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());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
 
}
}
}
 
5、字节流转成字符流
通过键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
 
readLine方法是字符流BufferedReader类中的方法。
 
而键盘录入的read方法是字节流InputStream的方法。
 
那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?
1
public class InputStreamReader
extends Reader
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
 BufferedReader in
   = new BufferedReader(new InputStreamReader(System.in))
2)
public class OutputStreamWriter
extends Writer
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器
 
 
示例:
import java.io.*;
 
class  TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象。
//InputStream in = System.in;
 
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
 
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
 
//BufferedReader bufr = new BufferedReader(isr);
 
 
//键盘的最常见写法。
BufferedReader bufr = 
new BufferedReader(new InputStreamReader(System.in));
// OutputStream out = System.out;
// OutputStreamWriter osw = new OutputStreamWriter(out);
// BufferedWriter bufw = new BufferedWriter(osw);
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
 
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值