OutputStream:字节输出流
- 结构图
FileOutputStream 文件字节输出流
构造方法
FileOutputStream提供4个常用的构造方法,其实底层只有一个。
构造方法 | 描述 |
---|---|
FileOutputStream(File file) | 使用File对象打开本地文件,并创建对象且使对象指向该文件。 |
FileOutputStream(String name) | 根据传入路径打开本地文件,并创建对象且使对象指向该文件。(该构造方法的源代码,其内部使用了File对象打开文件) |
FileOutputStream(File file, boolean append) | 打开文件,并使对象指向该文。件第二个参数决定字节写入文件末尾而还是开头【追加写入】 |
FileOutputStream(String name, boolean append) | 同上 |
public class Demo{
public static void main(String[] args) throws FileNotFoundException {
File f = new File("e:\\360sd\\1.txt");
FileOutputStream fos = new FileOutputStream(f,true);
}
}
注意:创建FileOutputStream对象,会打开File对象封装路径指向的文件,并让创建好的对象指向该文件。如果找不到路径或者指向的不是文件将抛出文件不存在异常。
写数据方法
写入方法 | 描述 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流 |
void write(byte[] b) | 将指定字节数组中的字节写入此文件输出流 |
void write(byte[] b, int off, int len) | 将字节数组中,指定下标和指定长度的字节写入此文件输出流 |
-
写入一个字节的数据 write(int b)
public class Demo{ public static void main(String[] args) throws IOException { File f = new File("e:\\360sd\\1.txt"); FileOutputStream fos = new FileOutputStream(f,true); fos.write(97); } } ---*--- 输出结果: e:\\360sd\\1.txt 文件中写入了 97 通过文本文档查看显示 a
注意:读写数据都会抛出IOException。(读写异常)
-
写入一个byte数组的数据 write(byte[ ] b)
public class Demo{ public static void main(String[] args) throws IOException { File f = new File("e:\\360sd\\1.txt"); FileOutputStream fos = new FileOutputStream(f,true); byte[] byt = {97,98,99,100}; fos.write(byt); } } ---*--- 输出结果: e:\\360sd\\1.txt 文件中写入了 97 98 99 100 通过文本文档查看显示 abcd
-
字符串转byte数组 (补充)
public class Demo{ public static void main(String[] args) throws IOException { File f = new File("e:\\360sd\\1.txt"); FileOutputStream fos = new FileOutputStream(f,true); byte[] byt = "中国四川".getBytes(); fos.write(byt); } } ---*--- 输出结果: e:\\360sd\\1.txt 文件中写入了 中国四川转换的字节数组 通过文本文档查看显示 中国四川
-
写入byte数组指定位置的指定长度的字节 write(byte[] b, int off, int len)
public class Demo{ public static void main(String[] args) throws IOException { File f = new File("e:\\360sd\\1.txt"); FileOutputStream fos = new FileOutputStream(f,true); byte[] byt = {97,98,99,100,101}; fos.write(byt,1,3); } } ---*--- 输出结果: e:\\360sd\\1.txt 文件中写入了 98 99 100 通过文本文档查看显示
将 3 个字节的数据,并从数组byt的 1 位置开始写入到输出流
-
写入数据换行 \r\n
public class Demo{ public static void main(String[] args) throws IOException { File f2 = new File("e:\\360sd\\1.txt"); FileOutputStream fos = new FileOutputStream(f2,true); byte[] bs = "\r\n".getBytes(); fos.write(97); fos.write(bs); fos.write(98); fos.close(); } } ---*--- 输出结果: a b
关闭流
关闭方法 | 描述 |
---|---|
void close() | 关闭此文件输出流并释放与此流关联的所有系统资源 |
复制文件/图片/视频
-
复制文件 基础版
public class Demo{ public static void main(String[] args) throws IOException { File f1 = new File("e:\\360sd\\1.txt"); File f2 = new File("e:\\360sd\\2.txt"); //创建新文件 f2.createNewFile(); //创建IO对象打开文件,指向文件 FileInputStream fis = new FileInputStream(f1); FileOutputStream fos = new FileOutputStream(f2); //暂存变量 int a; while ((a=fis.read())!=-1){//读一个字符,不为 -1 代表还有数据 fos.write(a);//写一个字符 } //查看复制的内容 FileInputStream fis1 = new FileInputStream(f2); System.out.print("复制的内容是:"); while ((a=fis1.read())!=-1){ System.out.print((char) a);//为了和文本文档中看到的一样强转为char } } } ---*--- 输出结果: 复制的内容是:ABCD e:\\360sd\\1.txt 文件通过文本文档查看显示 ABCD e:\\360sd\\2.txt 文件中写入了 65 66 67 68 通过文本文档查看显示 ABCD
-
复制文件 升级版
public class Demo{ public static void main(String[] args) throws IOException { File f1 = new File("e:\\360sd\\1.txt"); File f2 = new File("e:\\360sd\\2.txt"); //创建新文件 f2.createNewFile(); //复制文件 copyFile(f1,f2); //查看复制的文件内容 FileInputStream fis = new FileInputStream(f2); byte[] bs = new byte[1024]; while ((fis.read(bs))!=-1){ System.out.println("复制的内容是:"+new String(bs)); } } public static void copyFile(File a,File b){ if (!a.exists()) { System.out.println("源文件不存在!"); return; } try { FileInputStream fis = new FileInputStream(a); FileOutputStream fos = new FileOutputStream(b); //读写用的中转byte数组 byte[] bs = new byte[1024]; //读数据 while (fis.read(bs)!=-1){ //写数据 fos.write(bs); } //刷新缓冲区 fos.flush(); //关闭文件 fis.close(); fos.close(); System.out.println("复制完成!"); }catch (IOException e){ e.printStackTrace(); } } } ---*--- 输出结果: 复制完成! 复制的内容是:ABCD
-
复制图片
public class Oop{ public static void main(String[] args) throws IOException { File f1 = new File("e:\\360sd\\新建文件夹1\\图片.jpg"); File f2 = new File("e:\\360sd\\新建文件夹2\\图片(拷贝).jpg"); //打开文件,创建输入输出流对象指向文件 FileInputStream fis = new FileInputStream(f1); FileOutputStream fos = new FileOutputStream(f2); //通过读写复制 byte[] bs = new byte[1024]; int len; while((len=fis.read(bs))!=-1){ fos.write(bs,0,len); } //关闭文件 fis.close(); fos.close(); } } ---*--- 输出结果: 在f2对象封装的路径下复制了一个 图片(拷贝).jpg 文件
注意:此程序可以复制任意格式文件,就不演示视频文件复制了。
io异常处理
进行io操作会调用系统资源,所以我们处理异常时要保证占用的资源一定被释放掉。
-
try…catch…finally
public class Demo { public static void main(String[] args) { //变量定义在try外,否则finally块看不到 BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); }finally { //对象不为null,就关闭流 if (bis!=null) { try { bis.close(); }catch (IOException e){ e.printStackTrace(); } } if (bos!=null){ try { bos.close(); }catch (IOException e){ e.printStackTrace(); } } } } } ---*--- //这是处理io流保证资源是否的标准格式
-
JDK7改进方案:在try后的括号定义流对象
public class Demo { public static void main(String[] args) { try( //将流对象定义在此括号中 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); ) { byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); } } } ---*--- /* 将流对象定义在try后的()中,省去了finally块。 程序更简洁,推荐使用。 */
-
JDK9改进方案
public class HelloWorld { public static void main(String[] args) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); try(bis;bos) { byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); } } } ---*--- /* 在JDK7基础上改进,仅将流对象放在try后的()中, 创建流对象的异常依然需要方法来处理。 */
BufferedOutputStream 字节缓冲输出流
该类为字节输出流提供一个可设置大小的缓冲区,先将数据写入缓冲区,之后再一次写入目标文件。注意:真正的写数据还是字节输出流,该类仅提供一个缓冲区。
-
构造方法
构造方法 描述 BufferedOutputStream(OutputStream out) 为传入的字节输出流提供一个缓冲区以提高效率 BufferedOutputStream(OutputStream out, int size) 为传入的字节输出流提供一个缓冲区以提高效率,并可设置缓冲区大小 public class Demo { public static void main(String[] args) throws IOException { //创建字节缓冲输出流 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("h:\\360sd\\1.txt")); //写入一个byte数组数据 bos.write("ABC".getBytes()); bos.write("DEF".getBytes()); //关闭资源 bos.close(); } } ---*--- 输出结果: //h:\\360sd\\1.txt 文件中写入了ABCDEF
注意:缓冲输出流的使用和字节输出流相同
-
使用字节流和缓冲字节流耗时对比
public class Demo { public static void main(String[] args) throws IOException { long l1 = System.currentTimeMillis(); // method1(); //耗时87978毫秒 // method2(); //耗时131毫秒 // method3(); //耗时365毫秒 method4(); //耗时37毫秒 long l2 = System.currentTimeMillis(); System.out.println("耗时"+(l2-l1)+"毫秒"); } //一次读写一个 字节数据 public static void method1() throws IOException { FileInputStream fis = new FileInputStream("h:\\360sd\\视频.mp4"); FileOutputStream fos = new FileOutputStream("h:\\360sd\\视频(拷贝).mp4"); int by; while ((by=fis.read())!=-1){ fos.write(by); } fis.close(); fos.close(); } //一次读写一个 字节数组数据 public static void method2() throws IOException { FileInputStream fis = new FileInputStream("h:\\360sd\\视频.mp4"); FileOutputStream fos = new FileOutputStream("h:\\360sd\\视频(拷贝).mp4"); byte[] bs = new byte[1020]; int len; while ((len=fis.read(bs))!=-1){ fos.write(bs,0,len); } fis.close(); fos.close(); } //字节缓冲流 一次读写一个字节数据 public static void method3() throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("h:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("h:\\360sd\\视频(拷贝).mp4")); int by; while ((by=bis.read())!=-1){ bos.write(by); } bis.close(); bos.close(); } //字节缓冲流 一次读写一个字节数组数据 public static void method4() throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("h:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("h:\\360sd\\视频(拷贝).mp4")); byte[] bs = new byte[1024]; int len; while ((len=bis.read(bs))!=-1){ bos.write(bs,0,len); } bis.close(); bos.close(); } } ---*--- 输出结果: // method1(); //耗时87978毫秒 // method2(); //耗时131毫秒 // method3(); //耗时365毫秒 // method4(); //耗时37毫秒
注意:从输出结果可以看出,推荐使用 缓冲字节流+byte数组 形式,不推荐使用单字节读取形式。
InputStream:字节输入流
- 结构图
FileInputStream 文件字节输入流
构造方法
构造方法 | 描述 |
---|---|
FileInputStream(File file) | 打开file对象封装路径指向的文件,并创建对象指向该文件 |
FileInputStream(String name) | 打开name路径指向的文件,并创建对象指向该文件 |
public class Demo {
public static void main(String[] args) throws IOException {
File f = new File("h:\\360sd\\1.txt");
FileInputStream fis = new FileInputStream(f);
}
}
注意:创建FileOutputStream对象,会打开File对象封装路径指向的文件,并让创建好的对象指向该文件。如果找不到路径或者指向的不是文件将抛出文件不存在异常。
读数据方法
读取方法 | 描述 |
---|---|
int read() | 从此输入流中读取一个字节的数据 |
int read(byte[] b) | 从此输入流中读取一个字节数组的数据,返回真是读取到的字节的个数 |
int read(byte[] b, int off, int len) | 从此输入流读取len个字节数据,从off下标开始存储到字节数组 |
int available() | 返回可以从此输入流中读取(或跳过)的剩余字节数的估计值【查看还有多少个字节可以读】 |
-
读取一个字节数据 int read()
public class Demo { public static void main(String[] args) throws IOException { File f = new File("h:\\360sd\\1.txt"); FileInputStream fis = new FileInputStream(f); //读取一个字节数据 int a = fis.read(); System.out.println(a); System.out.println((char) a); } } ---*--- 输出结果: 97 a
注意:当读取数据时,返回值为 -1 说明没有可读取的字节。
-
读取一个字节数组的数据 int read(byte[] b) 返回真实读取到的数据个数
public class Demo { public static void main(String[] args) throws IOException { File f = new File("h:\\360sd\\1.txt"); FileInputStream fis = new FileInputStream(f); //创建byte数组,长度为所指文件字节数 byte[] bs = new byte[fis.available()];//获取当前文件剩余数据数 //读数据 fis.read(bs); //查看读取的数据 for (byte b : bs) { System.out.print(b+"\t"); System.out.println((char) b); } } } ---*--- 输出结果: 97 a 98 b 99 c 100 d 101 e 102 f 103 g
注意:available 方法返回当前输入流剩余的字节数,这里直接将byte数组长度设为输入流剩余的字节数,一次读取所有字节到 byte 数组。
-
补充 String(byte[] bytes, int off, int len) 将byte数组转位字符串,长度为len,起点为off
public class Demo { public static void main(String[] args) throws IOException { File f = new File("h:\\360sd\\1.txt"); FileInputStream fis = new FileInputStream(f); //创建读取数据用的byte数组 byte[] bs = new byte[5]; //读取数据到bs数组中,并返回真实读取到的数据个数 int len = fis.read(bs); //通过字节数组转字符串 while (len!=-1){ String s = new String(bs,0,len); System.out.print(s); len = fis.read(bs); } } } ---*--- 输出结果: abcdefg d
关闭流
关闭方法 | 描述 |
---|---|
void close() | 关闭此文件输入流并释放与此流关联的所有系统资源 |
复制文件
io异常处理
进行io操作会调用系统资源,所以我们处理异常时要保证占用的资源一定被释放掉。
-
try…catch…finally
public class Demo { public static void main(String[] args) { //变量定义在try外,否则finally块看不到 BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); }finally { //对象不为null,就关闭流 if (bis!=null) { try { bis.close(); }catch (IOException e){ e.printStackTrace(); } } if (bos!=null){ try { bos.close(); }catch (IOException e){ e.printStackTrace(); } } } } } ---*--- //这是处理io流保证资源是否的标准格式
-
JDK7改进方案:在try后的括号定义流对象
public class Demo { public static void main(String[] args) { try( //将流对象定义在此括号中 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); ) { byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); } } } ---*--- /* 将流对象定义在try后的()中,省去了finally块。 程序更简洁,推荐使用。 */
-
JDK9改进方案
public class HelloWorld { public static void main(String[] args) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\360sd\\视频1.mp4")); try(bis;bos) { byte[] bs = new byte[1024]; int len; while ((len = bis.read(bs)) != -1) { bos.write(bs); } }catch(IOException e){ e.printStackTrace(); } } } ---*--- /* 在JDK7基础上改进,仅将流对象放在try后的()中, 创建流对象的异常依然需要方法来处理。 */
BufferedInputStream 字节缓冲输入流
该类为字节输入流提供一个可设置大小的缓冲区,先将数据读入缓冲区,之后再一次读入内存中。注意:真正的读数据还是字节输入流,该类仅提供一个缓冲区。
-
构造方法
构造方法 描述 BufferedInputStream(InputStream in) 为传入的字节输入流提供一个缓冲区以提高效率 BufferedInputStream(InputStream in, int size) 为传入的字节输入流提供一个缓冲区以提高效率,并可设置缓冲区大小 public class Demo { public static void main(String[] args) throws IOException { //创建字节缓冲输入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("h:\\360sd\\1.txt")); //一次读取一个字节数据 int by; while ((by=bis.read())!=-1){ System.out.print((char) by); } //释放资源 bis.close(); } } ---*--- 输出结果: abcdefg //h:\\360sd\\1.txt 文件中存有abcdefg
注意:缓冲输入流的使用和字节输入流相同
-
使用字节流和缓冲字节流耗时对比
public class Demo { public static void main(String[] args) throws IOException { long l1 = System.currentTimeMillis(); // method1(); //耗时87978毫秒 // method2(); //耗时131毫秒 // method3(); //耗时365毫秒 method4(); //耗时37毫秒 long l2 = System.currentTimeMillis(); System.out.println("耗时"+(l2-l1)+"毫秒"); } //一次读写一个 字节数据 public static void method1() throws IOException { FileInputStream fis = new FileInputStream("h:\\360sd\\视频.mp4"); FileOutputStream fos = new FileOutputStream("h:\\360sd\\视频(拷贝).mp4"); int by; while ((by=fis.read())!=-1){ fos.write(by); } fis.close(); fos.close(); } //一次读写一个 字节数组数据 public static void method2() throws IOException { FileInputStream fis = new FileInputStream("h:\\360sd\\视频.mp4"); FileOutputStream fos = new FileOutputStream("h:\\360sd\\视频(拷贝).mp4"); byte[] bs = new byte[1020]; int len; while ((len=fis.read(bs))!=-1){ fos.write(bs,0,len); } fis.close(); fos.close(); } //字节缓冲流 一次读写一个字节数据 public static void method3() throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("h:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("h:\\360sd\\视频(拷贝).mp4")); int by; while ((by=bis.read())!=-1){ bos.write(by); } bis.close(); bos.close(); } //字节缓冲流 一次读写一个字节数组数据 public static void method4() throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("h:\\360sd\\视频.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("h:\\360sd\\视频(拷贝).mp4")); byte[] bs = new byte[1024]; int len; while ((len=bis.read(bs))!=-1){ bos.write(bs,0,len); } bis.close(); bos.close(); } } ---*--- 输出结果: // method1(); //耗时87978毫秒 // method2(); //耗时131毫秒 // method3(); //耗时365毫秒 // method4(); //耗时37毫秒
注意:从输出结果可以看出,推荐使用 缓冲字节流+byte数组 形式,不推荐使用单字节读取形式。
总结
1.创建字节流对象,必然会调用File类来打开指定路径的文件。
2.字节输出流可以选择是否追加写入。
3.字符/字节缓冲流可以看成字符/字节流的一套装备并可以设置加强的力度(缓冲区大小),带上装备的字符/字节流更加强大。所以推荐使用。
4.字节流可以读写任意文件数据,一般采用字节缓冲流一次读写一个byte数组数据的方式。