File的案例补充:
package File;
import java.io.File;
import java.io.IOException;
public class FileDiGuiDemo {
public static void main(String[] args) throws IOException {
File f = new File("D:\\develop\\IntelliJ IDEA 2021.3");
getFilePath(f);
}
public static void getFilePath(File file) {
//获取指定目录下的所有目录或文件
File[] fileArray = file.listFiles();
if (fileArray != null) {
for (File f : fileArray) {
if (f.isDirectory()){
getFilePath(f);
}
else {
System.out.println(f.getAbsolutePath());
}
}
}
}
}
输出结果:
字节流
字节流写数据
字节流抽象基类
- InputStream:此抽象类是所有字节输入流的所有类的超类。
- OutputStream:此抽象类是所有字节输出流的所有类的超类。
- 他们都所有子类都是以父类名作为后缀的,比如:FileOutputStream。
FileOutputStream:文件输出流用于将数据写入File。
- FileOutputStream(String name):创建文件输出流以指定的名称写入文件。
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
//创建字节输出流对象
//FileOutputStream创建文件输出流,然后将之写入指定文件中
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\fos.txt");
//将指定字节写入此文件输出流
fos.write(97);//ascii码97对应a
fos.write(57);//ascii码57对应9
//最后都需要释放资源
//void关闭此文件输出流并释放于此流相关联的任何系统资源
fos.close();
fos.txt中:
这里需要注意的是
FileOutputStream fos=new FileOutputStream(“ieda_test\src\IO\fos.txt”);
这条语句有三个功能:
①创建一个FileOutputStream对象fos。
②创建了一个文件fos.txt到指定目录下。
③将输出流对象fos写入fos.txt文件中。
④如果文件夹中有fos.txt了,那么会创建一个新的覆盖掉之前的。
⑤并且,通过这种输出流对象写入文件输出流的方式,文件以文本打开后显示的是输出流作为ascii码对应的字符。
如:输出流为97,显示为a
为了方便,可以使用getBytes()方法将字符串直接转换为ascii码,然后作为输出流写入。
byte[] a="abcde".getBytes();
fos.write(a);
字节流写数据的3种方式
字节流写数据的两个小问题
一、如何实现换行
windows:\r\n
linux:\n
mac:\r
for (int i=0;i<10;i++){
fos.write("hello\r\n".getBytes());
}
输出
二、如何实现追加写入
其实每次使用write写入都是最末尾进行追加,那为何这里还要实现追加写入呢?
因为这里的追加写入的意思其实是,每次使用不同的FileOutputStream对同一个文件进行追加写入:
比如之前这个fos.txt中已经有abcdf,
这个时候如果执行以下这段代码,fos.txt中就只有十行hello而没有abcdf了,因为这是从头重新写入了
public static void main(String[] args) throws IOException {
//创建字节输出流对象
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\fos.txt");
//写数据
for (int i=0;i<10;i++){
fos.write("hello\n".getBytes());
}
//释放资源
fos.close();
}
要实现不改变之前的内容,从abcdef后面开始写入就只需要在创建 FileOutputStream fos对象的时候,在后面加一个true。
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\fos.txt",true);
执行结果;
字节流写数据加异常处理
public static void main(String[] args) {
try{
//创建字节输出流对象
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\fos.txt",true);
//写数据
for (int i=0;i<10;i++){
fos.write("hello\n".getBytes());
}
//释放资源
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
像这样就完成了最基础的异常处理,但是这样的话,如果在write的过程中出现了IOException的异常,程序进入catch中就无法执行close释放资源操作了。所以为了避免出现这种情况,try,catch还有另外一个finally操作。
finally:在异常处理时提供finally块来执行所有清除操作。比如说IO流中的释放资源
特点:被finally控制的语句-定会执行,除非JVM退出。
```java
public class IODemo04 {
public static void main(String[] args) {
FileOutputStream fos = null;//为什么这里要声明在外面,并且赋初值null呢? 因为finally里获取不到try里面声明的fos,所以需要先声明在外面;并且为了防止fos没有被初始化,所以要先赋值一个null。
try{
//创建字节输出流对象
fos=new FileOutputStream("ieda_test\\src\\IO\\fos.txt",true);
//写数据
for (int i=0;i<10;i++){
fos.write("hello\n".getBytes());
}
//释放资源
fos.close();
}catch (IOException e){
e.printStackTrace();
}finally {
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\fos.txt");
//读取数据
int by=fis.read();
System.out.println(by);
System.out.println((char)by);
}
fis.read()读取fis文件的第一个字符,输出是以字符的ascii码输出的
输出结果:
这是只读取一次的情况,如果读取多次呢?
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\fos.txt");
//读取数据
int by=fis.read();
System.out.println(by);
System.out.println((char)by);
by=fis.read();
System.out.println(by);
System.out.println((char)by);
by=fis.read();
System.out.println(by);
System.out.println((char)by);
by=fis.read();
System.out.println(by);
System.out.println((char)by);
}
执行结果:
如果执行到了最后一个字符会返回什么呢?
返回-1
所以返回-1的时候就是读取完成的意思,可以以此为条件结束读取。
while(by!=-1){xxx}
一次读取多个字符
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\fos.txt");
byte[] bys=new byte[5];//一次读取5个字符数组
fis.read(bys);
System.out.println(new String(bys));
bys=new byte[5];//一次读取5个字符数组
fis.read(bys);
System.out.println(new String(bys));
bys=new byte[5];//一次读取5个字符数组
fis.read(bys);
System.out.println(new String(bys));
fis.close();
}
但需要注意:在**分段读取(比如一次读5个,多次读入)**的时候,换行符之类的符号也会作为一个字符读入。
如:/r/n读为两个字符
并且在这里,如果剩下可供读入的不足5个字符了,那么bys中只会将新读入的前几个替换掉,后面的不会变。
一次读入的话就不会出现这种情况。
public class IOInputDemo02 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\fos.txt");
byte[] bys=new byte[1024];//一次读取5个字符数组
int len;
while((len=fis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
fis.close();
}
}
执行结果:
hello
world
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\fos.txt");
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\copyFos.txt");
int by;
while ((by=fis.read())!=-1){
fos.write(by);
}
fis.close();
fos.close();
}
}
注意:每次使用完IO后都要释放资源。
package IO;
import java.io.*;
public class PhotoCopyDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("ieda_test\\src\\IO\\ddd.jpg");
FileOutputStream fos=new FileOutputStream("ieda_test\\src\\IO\\img_copy.jpg");
int len;
byte[] bys=new byte[1024];
while ((len=fis.read(bys))!=-1){
fos.write(bys,0,len);
}
fos.close();
fis.close();
}
}
字节缓冲流
字节缓冲流和之前的字节流的区别:
字节缓冲流在使用的时候向底会输出流或入字节,而不必为写入的每个字节导致底层系统的调用。所以他的效率会更好一些。