文件IO 1(接上多线程14)
常用的文件方法
文件删除
接上上一篇利用代码创建文件,这里则是利用代码删除文件 :
file.delete();//删除文件
file.deleteOnExit();//在进程退出时候删除
public class Demo {
public static void main(String[] args) throws InterruptedException, IOException {
File file1 = new File("./111.txt");
file1.createNewFile();
File file2 = new File("./222.txt");
file2.createNewFile();
Thread.sleep(1000);
boolean result1= file1.delete();//删除文件
file2.deleteOnExit();//在进程退出时候删除
System.out.println(result1);
Thread.sleep(10000);
}
}
可以自行去运行一下,我们可以打开存放当前文件目录,观察变化,这里就不放图了,直接说结果:file1和file2同时被创建,但过了1秒后,file1被删除,再过了10秒,进程结束之后,file2才被删除
在office系列产品,会使用到deketeOnExit,在我们编辑文档的时候,他会自动创建一个隐藏文件,在正常退出的时候,就会调用deleteOnExit将这个隐藏文件清除,如果是异常退出(断电、电脑重启等),当下次打开文档的时候会读取隐藏文件询问是否恢复。不恢复就调用detele()将文档删除。
list与listFile
list可以得到目录下所有的文件名字,listFile则是得到目录下的对象,可以进行更多的操作,单纯的比对是看不出上面结果。
public class Demo {
public static void main(String[] args) {
//list是返回目录对象下的所有文件名
File file = new File("./111.txt");//文件
File file1 = new File("C:/");//目录
String[] r = file.list();
String[] r1 = file1.list();
System.out.println(r);//针对文件无法使用list,必须针对目录
System.out.println(Arrays.toString(r));
System.out.println(r1);//无法直接拿到地址
System.out.println(Arrays.toString(r1));//Arrays.toString帮忙转义
//list只能列出当前目录下的子目录,无法列出子目录下的全部内容
File[] r2 = file1.listFiles();//得到的是file目录下所有的对象,list得到的是文件名,
System.out.println(Arrays.toString(r2));
}
}
mkdir与mldirs
mkdir可以创建一个目录,但无法在这个目录下连续创建子目录。
mkdirs则可以连续创建子目录。
public class Demo {
public static void main(String[] args) {
File file = new File("./test");
File file1 = new File("./test1/111/222/333");
file.delete();//清空之前创建的目录
file1.delete();
boolean result = file.mkdir();//创建一个叫做test的目录
//但无法创建多级目录,想要创建多级目录则需要使用mkdirs
boolean result1 = file1.mkdirs();
System.out.println("result = " + result);
System.out.println("result1 = " + result1);
}
}
renameTo
renameTo可以更改文件名字,也可以移动当前文件夹到其他目录。
public class Demo {
public static void main(String[] args) throws InterruptedException {
File file = new File("./test");
File newFile = new File("./test2");
File newnewFile = new File("./src/test2");
newnewFile.delete();
Thread.sleep(1000);//拉长时间,方便打开目录观测
file.mkdir();
Thread.sleep(1000);
boolean r = file.renameTo(newFile);//将test下的文件名字修改成test2
Thread.sleep(1000);
boolean r1 = newFile.renameTo(newnewFile);//将test2移动到src文件
Thread.sleep(1000);
}
}
重命名操作和移动操作在操作系统看来本质是一样的,速度极快(O(1),等于我们常用的剪切)
流
java提供的流非常多,具体可以分成以下两大类
1.字节流:
读写文件,以字节为单位,针对二进制文件使用。比较有代表性的有下面两个:
InputStream 输入流
我们在test文件里输入了hello,来看看打印结果:
public class Demo7 {
public static void main(String[] args) throws IOException {
InputStream inputStream = null;
try{
inputStream = new FileInputStream("./test.txt");//创建对象成功
}finally {//为了防止出现意外终止进程,我们用finally来保证文件一定关闭
inputStream.close();//关闭文件
}
}
}
FileInputStream的参数可以填写文件路径(绝对相对路径)、File对象。
InputStream流对象不仅可以给文件提供操作,还可以用于网络编程。
read():一次读取一个字节,返回类型是int
public class Demo7 {
public static void main(String[] args) throws IOException {
try( InputStream inputStream = new FileInputStream("./test.txt");){
while(true){
int data = inputStream.read();
if(data == -1){
break;
}
System.out.println(data);
}
}
}
}
运行结果
在这里读取data是按照字节取出打印,因为我们是纯英文,对应十进制的ascil码表来查看可以翻译出来。
注:汉字对应UTF-8码表,建议十六进制打印(System.out.printf("0x%x\n",data[i]);)方便查找
read(bate[] b):一次读取若干个字节,存放在数组里。
public class Demo7 {
public static void main(String[] args) throws IOException {
try( InputStream inputStream = new FileInputStream("./test.txt");){
byte [] data = new byte[1024];//自定义数组长度
int n = inputStream.read(data);//n为字节数量
System.out.println(n);
for (int i = 0;i <n; i++){
System.out.println(data[i]);
}
}
}
}
在读取文件时,会将字节数组填满,若填不满,就将剩下的字节能填多少填多少。
read(bate[] b,int off , int len):将输入流中最多 len
个数据字节读入字节数组。
off:在其处写入数据的数组 b
的初始偏移量。
public class Demo7 {
public static void main(String[] args) throws IOException {
try( InputStream inputStream = new FileInputStream("./test.txt");){
while (true){
byte [] data = new byte[1024];
int n = inputStream.read(data,0,10);
if(n == -1){
break;
}
System.out.println(n);
for (int i = 0;i <n; i++){
System.out.println(data[i]);
}
}
}
}
}
这里换十六进制打印:
OutputStream 输出流
write的参数与上面read的参数差不多,一次一个字节、一次若干字节,一次取数组一部分字节。
public class Demo8 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("./output.txt")){
outputStream.write(97);
}catch (IOException e){
throw new RuntimeException(e);
}
}
}
如果没有创建文件的话,OutputStream会尝试创建一个文件,并且写入。但OutputStream写入同一个文件的时候,会在打开文件的时候会清空上次的写内容。
若我们不想清空内容,我们可以使用追加写的方法:
下面是一次性写入若干个字节
public class Demo {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("./output.txt")){
byte[] bytes = {98,97,99};
outputStream.write(bytes);
}catch (IOException e){
throw new RuntimeException(e);
}
}
}
一次性写入一数组的一部分:
public class Demo8 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("./output.txt",true)){
byte[] bytes = {97,98,99};
outputStream.write(bytes,1,1);
}catch (IOException e){
throw new RuntimeException(e);
}
}
}
2.字符流:
读写文件以字符为单位,针对文本文件使用。比较有代表性的有下面两个:
Reader 输入流
read():一次读一个字符。
public class Demo9 {
public static void main(String[] args) {
try(Reader reader = new FileReader("./test.txt")) {
while(true){
int a = reader.read();
if(a == -1){
break;
}
System.out.println((char) a);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
read(char[] cbuf):读取字符数组,尽肯把数组填满,返回值是字符的实际个数。
read(CharBuffer target):CharBaffer相当于对char[]进行封装
public class Demo9 {
public static void main(String[] args) {
try(Reader reader = new FileReader("./test.txt")) {
while(true){
char[] buf = new char[1024];
int a = reader.read(buf);
if(a == -1){
break;
}
for(int i = 0;i<a;i++) {
System.out.println((char) buf[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
read(char[],int off,int len):读取数组里一部分字符。
public class Demo9 {
public static void main(String[] args) {
try(Reader reader = new FileReader("./test.txt")) {
while(true){
char[] buf = new char[1024];
int a = reader.read(buf,1,1);
if(a == -1){
break;
}
for(int i = 0;i<a;i++) {
System.out.println(buf[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Writer 写入
这写入也和上面一样,有三相似的版本,写入一个字符、写入数组、写入数组的一部分,使用方法与OutputStream 相差不大。在这之外,还有个特殊的功能,用于写入字符串(String str)。
我们在使用流的时候,先要确认是文本文件还是二进制文件,其次才是选择对应的流读和写。