字节流
1.基本操作与字符流类相同
2.但它不仅可以操作字符,还可以操作其他媒体文件
字节流的缓冲区
同样是提高了字节流的读写效率。
字节流实例:
/*
字符流:
FileReader
FileWriter。
BufferedReader
BufferedWriter
字节流:
InputStream OutputStream
需求,想要操作图片数据。这时就要用到字节流。
复制一个图片.
*/
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");
// int num = fis.available();
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();
}
}
拷贝图片
/*
复制一个图片
思路:
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("f:\\2.bmp");
fis = new FileInputStream("f:\\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("写入关闭失败");
}
}
}
}
mp3的复制(通过缓冲区)
/*
演示mp3的复制。通过缓冲区。
BufferedOutputStream
BufferedInputStream
*/
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("f:\\1.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("f:\\2.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("f:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("f:\\1.mp3"));
int by = 0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
自定义字节流的缓冲区
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();
}
}
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
读取键盘录入
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);
}
}
}
字节流转换流
/*
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?
*/
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();
}
}
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个。
通过三个明确来完成。
1.明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer。
2.操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3.当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。
实例:
/*
需求:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
*/
class TransStreamDemo2{
public static void main(String[] args) throws IOException{
System.setIn(new FileInputStream("PersonDemo.java"));
System.setOut(new PrintStream("zzz.txt"));
//键盘的最常见写法。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
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();
}
}