文件内容操作
一:字节流
字节流:以字节为单位读写数据.
常用的类主要有:InputStream,OutputStream
核心操作:
(1)通过构造方法,打开文件
(2)通过read方法,读文件内容
(3)通过writer方法,写文件内容
(4)通过close方法,关闭文件.
1.1:InputStream
1.1:构造方法:
java
InputStream inputStream = new FileInputStream("d:/test.txt") ;
1.1.2:read()方法:
版本一 :无参数,一次读取一个字节,读取到的内容,就通过返回值来表示了.
既然一次读一个字节,返回值应该是byte类型,为什么返回int??
(1)1byte能够读取的访问0-255(无符号),但实际上byte类型是有符号的,范围是-127-128,我们期望是0-255,如果返回的类型是int ,则可以满足需求,通过int类型就可以确保读出来的字节都是整数.
(2)0-255都是表示读取的内容,256个数字都表示读取到了内容.但如果读取不到内容,就需要额外标记"到达文件末尾"返回-1这种情况.那么就存在257种情况,返回byte就不能达到.
(3)257种情况,为什么不用short,而用int??
计算机发展到现在,空间已经不再是核心矛盾了.存储设备成本越来越便宜(近段时间).
但是,随着CPU越来越强大,单次处理的数据,也变得越来越长了:
对于32位CPU,一次就是处理4个字节的数据,此时要是使用short,操作系统内部其实还是把short转成int,再按int来处理
对于64位CPU来说,一次就能处理8个字节的数据了,相比之下,short就能没什么意义了.
版本二 :带有一个参数,byte[]
传入一个字符数组.
java
byte[] bytes = new byte[1024];//先准备好一个空的字节数组
int n = inputStream.read(bytes);
//方法执行完毕后,把读到的数据放到字节数组中
//返回值表示成功读取到的字节数
//如果返回值为-1,则表示未成功读到任何数据
一次读取数组的长度个字节,如果不够,能读多少就读多少.
java
public class Demo2 {
public static void main(String[] args) throws IOException {
InputStream inputStream =new FileInputStream("d:/text.txt");
while(true){
int n = inputStream.read();
if(n==-1){
break;
}
System.out.printf("0x%x ",n);
}
}
}
java
public class Demo1 {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream
("E:\\img\\图书馆\\微信图片_20240324210435.jpg") ;
while(true){
byte[] bytes = new byte[1024];//先准备好一个空的字节数组
int n = inputStream.read(bytes);
//方法执行完毕后,把读到的数据放到字节数组中
//返回值表示成功读取到的字节数
//如果返回值为-1,则表示未成功读到任何数据
System.out.println("n = "+n);
if(n==-1){
break;
}
for (int i = 0; i <n ; i++) {
System.out.printf("0x%x ",bytes[i]);
}
System.out.println();
}
}
}
上述两种read方法中,哪个效率更高??
read():频次高,但一次读的东西太少.
read(bytes):频次低,一次读的东西多.
每次调用read,都是要通过系统api,来访问应硬盘的,访问硬盘是非常低效的操作,但一次读的东西读,还是读的东西少,开销其实是差不多的,所以read(bytes)效率是更高的.
第三个版本:
和第二个版本差不多,第二个版本,把读到的数据往整个数组填充,但三个版本,从下标off开始,最多填充len那么长.
有的时候,可能需要一个数组,里面的不同的部分表示不同的含义.
1.1.3:关闭文件:close
为什么要关闭文件??
打开文件的时候,会在操作系统的内核,PCB这样的结构体中,给"文件描述符表"**添加一个元素,**这个元素就是表示当前打开的文件的相关信息.
但文件描述符表(相当于一个顺序表),里面的长度是固定的,存在上限,不能自动扩容,如果一直打开文件,而不关闭,就会使这个文件描述符表被占满,一旦占满之后,再次尝试打开,就会打开文件失败(其他的操作,网络通信相关的操作,也可能会收到影响).
所以必须close,但在close前面如果出现异常/return,此时close就执行不到了.
使用finally:保证close()操作一定会被执行到
java
public class Demo2 {
public static void main(String[] args) throws IOException {
InputStream inputStream =new FileInputStream("d:/text.txt");
try{
while(true){
int n = inputStream.read();
if(n==-1){
break;
}
System.out.printf("0x%x ",n);
}
}finally {
inputStream.close();
}
}
}
使用try:必须要实现Closeable接口的类,才能放到try()中:
java
public class Demo3 {
public static void main(String[] args) throws IOException {
try( InputStream inputStream =new FileInputStream("d:/text.txt")){
while(true){
int n = inputStream.read();
if(n==-1){
break;
}
System.out.printf("0x%x ",n);
}
}
}
}
1.2:OutputStream
1.2.1:write()
版本一:一次write 一个字节,参数是 int 类型
版本二:一次write若干字节,会把参数数组里所有的字节都写入文件中.
版本三:一次write若干字节,把数组从off下标开始,连续写len个字节
java
public class Demo4 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("d:/text.txt")){
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里我们发现:按照写方式打开文件的时候,会把文件原有的内容清空掉(不是write清空的,而是打开操作清空的)
默认的写方式打开,会清空,如果使用"追加写"方式打开,就可以了.
java
public class Demo4 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("d:/text.txt",true)){
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
二:字符流
字符流:以字符为单位读写数据
常用的类主要有:Reader,Writer
2.1:Reader
这里常用的是第一个方法,表示一次读一个字符(可能是两个字节,也可能是三个字节),返回类型为char ,占两个字节.
java
public class Demo1 {
public static void main(String[] args) throws FileNotFoundException {
try(Reader reader=new FileReader("d:text.txt")){
while(true) {
int c = reader.read();
if (c == -1) {
break;
}
char ch = (char) c;
System.out.println(ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
java
public class Demo2 {
public static void main(String[] args) {
try(Reader reader = new FileReader("d:/text.txt")){
while(true){
int c = reader.read();
if(c==-1){
break;
}
char ch = (char) c;
System.out.print(ch+" ");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
IDEA采用utf-8编码方式,一个汉字是占3个字节,但read一次读三个字节,但返回类型是char, 占两个字节,明显是不对的啊??
实际上,Java对上述的数据进行了编码转换.
read在读取汉字的时候,能够识别此时采用的是utf-8的编码方式,所以读的时候,读的就是三个字节,但返回成一个char的时候,把utf-8的编码方式,转成了unicode,在unicode中,一个汉字就是2个字节.
举个栗子:
假设读到了一个字符"你",此时Java通过查询unicode编码表,找到"你"这个字符的值,此时这个值就对应两个字节,就可以返回了.
2.2:Writer
一般使用第二种方法.
这些writer()方法,也是会把原来的内容清空的,所以也需要采用"追加写"的方式,让它不要清空原来的内容.
java
public class Demo3 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("d:text.txt",true)){
writer.write("hello");
} catch (IOException e) {
e.printStackTrace();
}
}
}