字节流
一、概述
- 基本操作与字符流类相同。
- 但他不仅可以操作字符,还可以操作其他媒体文件。
两个基类:InputStream和OutputStream
二、基本演示
拷贝一个txt文件,这个在前一节已经演示多次。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoStreamDemo01 {
public static void main(String[] args) throws IOException {
// demo_write();
demo_read();
}
private static void demo_read() throws IOException {
FileInputStream fis = new FileInputStream("demoBytes.txt");
int ch = 0;
byte[] bytes = new byte[fis.available()];//小文件可以这么用,大文件还是要选择下面的操作。
fis.read(bytes);
System.out.println(new String(bytes));
// int len = 0;
// System.out.println(fis.available());
// while((len=fis.read(bytes)) != -1){
// System.out.println(new String(bytes, 0, len));
// }
}
public static void demo_write() throws IOException {
FileOutputStream fos = new FileOutputStream("demoBytes.txt");
byte[] bytes = "我爱北京天安门".getBytes();
fos.write(bytes);
fos.close();
}
}
整理:使用方法几乎和字符流一模一样,但是字节数组转String要记住用String构造函数String(byte[] bs, int offset, int length)。然后还要记住那些常用函数的参数和返回值,这很重要。至于字节流与字符流的本质区别这里毕老师还没有讲到,也就等讲到再记录!
注意:有个特殊方法available可以获取下个操作的字符长度。所以新建流后使用可以得到文件大小。这样可以直接新建文件大小的数组而不需要while循环。但是当文件过大时,这种方法将可能给内存带来巨大负担!因此不建议使用。
三、练习
拷贝一个MP3文件,下面列出了四种方法。其中第三种和第四种是不建议使用的。尤其是第四种,效率极其缓慢。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyMp3Test {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
copy_4();
}
// 千万不要用,效率没有!
public static void copy_4() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\4.mp3");
int ch = 0;
while((ch =fis.read())!=-1){
fos.write(ch);
}
fos.close();
fis.close();
}
//不建议。
public static void copy_3() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\3.mp3");
byte[] buf = new byte[fis.available()];
fis.read(buf);
fos.write(buf);
fos.close();
fis.close();
}
public static void copy_2() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("c:\\2.mp3");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while((ch=bufis.read())!=-1){
bufos.write(ch);
}
bufos.close();
bufis.close();
}
public static void copy_1() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
fis.close();
}
}
思考:用字符流能不能拷贝MP3文件?
不能:因为字符流读完了以后不直接输出,在此之前要查个编码表~~如果查表不到,得到的目的数据很可能就是乱码一通~~~
键盘录入示例
说明:键盘本身就是一个标准的输入设备。对于Java而言,对于这种输入设备都有对应的对象。
public static void main(String[] args) throws IOException {
readKey();
}
private static void readKey() throws IOException {
InputStream in = System.in;//寻找系统中的方法,发现了System.in
int ch = in.read();//阻塞式方法
//此时只能录入一个字符,如果输入a,则返回97
System.out.println(ch);
//注意:流对象就这一个,如果调用in.close();则再也打不开这个流System.in了,属于默认输入输出流,不需要关闭
}
需求:获取用户键盘录入的数据,并将数据变成大写显示在控制台上。如果用户输入的是over,结束键盘录入。
public static void main(String[] args) throws IOException {
readKey2();
}
public static void readKey2() throws IOException {
/*
* 获取用户键盘录入的数据,
* 并将数据变成大写显示在控制台上,
* 如果用户输入的是over,结束键盘录入。
*
* 思路:
* 1,因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。
* 2,那就需要一个容器。StringBuilder.
* 3,在用户回车之前将录入的数据变成字符串判断即可。
*
*/
//1,创建容器。
StringBuilder sb = new StringBuilder();
//2,获取键盘读取流。
InputStream in = System.in;
//3,定义变量记录读取到的字节,并循环获取。
int ch = 0;
while((ch=in.read())!=-1){
// 在存储之前需要判断是否是换行标记 ,因为换行标记不存储。
if(ch=='\r')
continue;
if(ch=='\n'){
String temp = sb.toString();
if("over".equals(temp))
break;
System.out.println(temp.toUpperCase());
sb.delete(0, sb.length());
}
else
//将读取到的字节存储到StringBuilder中。
sb.append((char)ch);
// System.out.println(ch);
}
}
观察上面的代码,可以发现和上一节的“读取一行数据”的代码十分相似。我们希望采用上一节的BufferedReader方法来读取整行。那么,怎么将InputStream这样的字节流转换成BufferedReader可以接受的字符流呢?查找Reader类(字符流的祖宗,为什么呢?回忆一下:字符流的祖宗是Reader和Writer;字节流的祖宗是InputStream和OutputStream)我们找到了一个叫做InputStreamReader的类,他是这样表述的“InputStreamReader是桥字节流和字符流:它读取字节并使用指定的 charSet
解码成字符”。试着使用一下,如下:
public static void main(String[] args) throws IOException {
//字节流。
InputStream in = System.in;
//将字节转成字符的桥梁。装换流。
InputStreamReader isr = new InputStreamReader(in);
//字符流。
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
}
这样,就很轻松地完成了我们的任务。而我们上面用到的InputStreamReader叫做转换流,它的作用是将字节解码成字符。
那么字符到字节有没有转换呢?查询我们找到了OutStreamWriter:将要写入流中的字符编码成字节。使用与上面类似。最终我们可以借助下图梳理一下,是怎么从字节流输入,转换为字符流操作,在转换回字节流输出到控制台。
把上面的代码缩写一下,得到下面简化版的代码,就是我们更常用的形式了。要注意的是,向缓冲区写入新行后要进行刷新操作才能打印到控制台。
//简化版代码
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;
}
// System.out.println(line.toUpperCase());
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();//要刷新
}
新需求:
1.将键盘录入的数据写入到一个文件中。
把上面的System.out写为路径
2.把文件读入到控制台
把上面的system.in改成路径
3.将一个文件中的内容复制到另一个文件中
把上面两个全部改为路径
我最近也是在不断的学习中,水平有限,如果有什么意见或建议请下方评论哦,我将十分感谢。
如果觉得有收获可以关注一波~~~