1. 使用文件输入流读取文件数据 int d = fis.read()
文件流常用的构造器(输入输出都一样)
FileInputStream(File file)------------------------先实例化file 传入fileFile file = new File("./fos.dat");
FileInputStream fis = new FileInputStream(file);//读操作
FileInputStream(String filename)--------------直接写抽象路径 少写一行FileInputStream fis = new FileInputStream(",/fos.dat");
难点: InputStream上定义了读取字节的方法 输入输出流对象. read()
- 读取1个字节,并以int形式返回。而返回的int值中只有"低八位"有数据(就是读取到的1字节的内容)。
- 如果返回的int值为整数-1,则表达流读取到了末尾(不可再通过这个流读取到任何数据了)。
//读取当前目录下的fos.dat文件中的字节数据
// File file = new File("./fos.dat");
// FileInputStream fis = new FileInputStream(file);//读操作
// FileOutputStream fos = new FileOutputStream(file);//写操作
FileInputStream fis = new FileInputStream("./fos.dat");
/*
fos.dat文件内容:
00000001 00000010
第一次调用:int d = fis.read();//读取文件的第一个字节
fos.dat文件内容:
00000001 00000010
^^^^^^^^
读取该字节
返回值d的2进制样子:00000000 00000000 00000000 00000001
|-------自动补充24个0------| ^^^^^^^^
本次读取的
*/
int d = fis.read();
System.out.println(d); //输出1
/*
第二次调用:d = fis.read();//读取文件的第二个字节
fos.dat文件内容:
00000001 00000010
^^^^^^^^
读取该字节
返回值d的2进制样子:00000000 00000000 00000000 00000010
|-------自动补充24个0------| ^^^^^^^^
本次读取的
*/
d = fis.read();
System.out.println(d);//输出2
/*
第三次调用:d = fis.read();//读取文件的第三个字节
fos.dat文件内容:
00000001 00000010 没有数据了
^^^^^^^^
文件末尾了
返回值d的2进制样子:11111111 11111111 11111111 11111111
|-----------自动补充32个1-----------|
*/
d = fis.read();
System.out.println(d);//输出-1
fis.close();
}
}
2.复制文件(输入再输出)
先声明int d----while循环判断d=fis.read不等于-1------fos.write
读取一个字节并输出
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("./10904.jpg");
FileOutputStream fos=new FileOutputStream("./image.jpg");
int d;
long start = System.currentTimeMillis();//获取当前系统时间的毫秒值
//一开始嫌麻烦 d初始化并赋值了 不可以! 每一遍赋值不能为-1
while((d = fis.read())!=-1){//每次循环先读取1个字节,判断是否读取到末尾
fos.write(d);//没有读取到末尾就将读取的字节写入复制的文件中
}
long end = System.currentTimeMillis();
System.out.println("复制完毕!耗时:"+(end-start)+"ms");
fis.close();
fos.close();
前后时间一减 知道花了多长时间复制文件 System.currentTimeMillis();
package io;
public class Demo {
public static void main(String[] args) {
//自1970-01-01 00:00:00到当前系统时间所经过的毫秒
// 用long值 因为int才21亿不够用
long now = System.currentTimeMillis();
System.out.println(now);
now = now/1000/60/60/24/365;
System.out.println(now);//52年
long max = Long.MAX_VALUE;
max = max/1000/60/60/24/365;
System.out.println("公元:"+(max+1970));//公元292473178
}
}
块读写操作
提高每次读写的数据量,减少读写次数可以提高读写效率 时间消耗在来回跑的路上
一组字节一次性读写操作称为:块读写操作
InputStream字节输入流的超类上规定了块读操作:
byte[] data = new byte[3];
int read(byte[] data)
一次性读取给定的字节数组data总长度的字节量并装入到该数组中
返回值为实际读取到的字节数。如果返回值为整数-1则表达流读取到末尾了
一个bit可以存一个8位2进制
01111111 127
第一位当成符号位去用了 0为正 1为负
块读演示
原文件内容(5个字节):
11001100 10101010 11110000 00001111 01010101int len=0;
//二进制形式data:{00000000,00000000,00000000}
byte[] data = new byte[3];
第一次调用:
len = fis.read(data);//data长度为3,因此一次性要读取3个字节
原文件内容:
11001100 10101010 11110000 00001111 01010101
^^^^^^^^ ^^^^^^^^ ^^^^^^^^
本次读取到的3个字节内容data:{11001100,0101010,11110000}
数组的三个字节为本次实际读取内容
len=3;//len为整数3,表达本次实际读取到了3个字节
第二次调用:
len = fis.read(data);//data长度为3,因此一次性要读取3个字节
原文件内容:
11001100 10101010 11110000 00001111 01010101 没有数据了
^^^^^^^^ ^^^^^^^^ ^^^^^^^^
本次实际读取到的2字节data:{00001111,01010101,11110000}
^^^^^^^^ ^^^^^^^^ |-旧数据-|
|-本次读取的新数据-|
len=2;//len为整数2,表达本次实际读取到了2个字节
第三次调用:
len = fis.read(data);//data长度为3,因此一次性要读取3个字节
原文件内容:
11001100 10101010 11110000 00001111 01010101 没有数据了
^^^^^^^^ ^^^^^^^^ ^^^^^^^^
本次没有读取到任何数据data:{00001111,01010101,11110000}
|---------旧数据----------|len=-1;//len为整数-1,表达已经是流的末尾了,本次没有读取任何数据。
8位2进制 1个字节
00000000 1byte
1024byte 1kb
1024kb 1mb
1024mb 1gb
1024gb 1tb
1024tb 1pb
块写操作
OutputStream字节输出流的超类上,定义了块写操作
void write(byte[] data)
一次性将给定的字节数组中所有字节写出void write(byte[] data,int offset,int len)
一次性将给定的字节数组data中从下标offset处开始的连续len个字节
一次性写出
public class CopyDemo2 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("./wnwb.exe");
FileOutputStream fos = new FileOutputStream("./wnwb_cp.exe");
int len;
byte[] data = new byte[1024*10];//10kb 计算表达式比10240更好理解
long start = System.currentTimeMillis();
//传入字节数组data
while((len = fis.read(data))!=-1){
fos.write(data,0,len);
}
long end = System.currentTimeMillis();
System.out.println("复制完毕!耗时:"+(end-start)+"ms");
fis.close();
fos.close();
}
}
复制后的文件比源文件大 len表示文件多少可用字节
3.写出文本数据 getBytes((StandardCharsets.UTF_8) 字符串转字节数组
/**
* 使用输出流写出文本数据
*/
public class eWriteStringDemo {
public static void main(String[] args) throws IOException {
//向文件中写入文本数据
FileOutputStream fos = new FileOutputStream("demo.txt");
String line = "和我在成都的街头走一走,哦哦哦哦。";
/*
UTF编码:unicode传输编码
UTF里面包含了全世界所有在用的流行文字
英文:1个字符占1个字节,维持ASC部分内容
中文:1个字符占3个字节
*/
byte[] data = line.getBytes(StandardCharsets.UTF_8);
fos.write(data);
line = "直到所有的灯都熄灭了也不停留。";
data = line.getBytes(StandardCharsets.UTF_8);
fos.write(data);
System.out.println("写出完毕!");
fos.close();
}
}
package io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/**
* 实现一个简易记事本工具:
* 程序启动后将用户在控制台输入的每一行字符串都写入到文件note.txt中。
* 如果用户单独输入"exit"则程序退出。
*
* 你好
* 嘿嘿
* 呵呵
* exit
*
* 文件:
* 你好嘿嘿呵呵
*/
public class Test2 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("note.txt");
Scanner scanner = new Scanner(System.in);
System.out.println("请开始输入内容,单独输入exit退出。");
while(true){
String line = scanner.nextLine();//1获取输入的一行字符串
if("exit".equalsIgnoreCase(line)){//2如果为exit,则退出
break;
}
//3将内容写入文件
byte[] data = line.getBytes(StandardCharsets.UTF_8);
fos.write(data);
}
fos.close();
System.out.println("再见!");
}
}
4.fos覆盖与追加
5.阅读文本数据
public class eReadStringDemo {
public static void main(String[] args) throws IOException {
//将当前源代码读取出来并输出到控制台上
File file = new File("./src/main/java/io/ReadStringDemo.java");
FileInputStream fis = new FileInputStream(file);
//创建与文件等长的字节数组
byte[] data = new byte[(int)file.length()];
//核心的步骤:先读取对应的字节,再将字节还原为字符串
fis.read(data);//一次性将文件所有字节读入数组
String line = new String(data, StandardCharsets.UTF_8);
System.out.println(line);//将转换后的字符串输出到控制台
fis.close();
}
}
6.高级流
public class eReadStringDemo {
public static void main(String[] args) throws IOException {
//将当前源代码读取出来并输出到控制台上
File file = new File("./src/main/java/io/ReadStringDemo.java");
FileInputStream fis = new FileInputStream(file);
//创建与文件等长的字节数组
byte[] data = new byte[(int)file.length()];
//核心的步骤:先读取对应的字节,再将字节还原为字符串
fis.read(data);//一次性将文件所有字节读入数组
String line = new String(data, StandardCharsets.UTF_8);
System.out.println(line);//将转换后的字符串输出到控制台
fis.close();
}
}
缓冲区 flush
/**
* 缓冲流写出时的缓冲区问题
*/
public class fFlushDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("bos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
String line = "和我在成都的街头走一走,哦哦哦哦~";
bos.write(line.getBytes(StandardCharsets.UTF_8));
/*
缓冲输出流的flush方法会强制将缓冲流中已经缓冲的数据一次性写出
flush方法是在接口:Flushable中定义的
而字节输出流的超类OutputStream实现了该接口,这以为这所有字节输出流
都具有该方法。
但是只有缓冲流真正实现了flush应有的功能。其他的高级流flush方法的实现
都是调用其连接的流的flush方法,将该动作传递下去。
*/
// bos.flush();//flush:冲水
System.out.println("写出完毕!");
//缓冲输出流的close方法中会自动调用一次flush确保所有数据关闭前写出
bos.close();
}
}