黑马程序员-Java IO输入与输出-day20

时间:2022-12-16 10:59:11

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

1、IO流——File概述

File类

1.用来将文件或者文件夹封装成对象

2.方便对文件与文件夹的属性信息进行操作。

3.File对象可以作为参数传递给流的构造函数

4.了解File类中的常用方法。

流只能操作数据,而想操作文件或者文件夹,则必须使用File对象

separator:与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串

import java.io.*;
public static void consMethod()
{
//将a.txt封装成file对象,可以将已有的和未出现的文件或者文件夹封装成对象。
File f1 = new File("a.txt");
File f2 = new File("C:\\abc","b.txt");
File d = new File("C:\\abc");
File f3 = new File(d,"c.txt");

sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);
//封装成相对路径,则打印相对路径;反之则反。
//跨平台的目录分隔符:separator
//File f4 = newFile("C:\\abc\\a.txt");
File f4 = newFile("C:"+File.separator+"abc"+File.separator+"a.txt");//将路径分隔符替换成跨平台的separator,方便跨平台使用
sop(f4);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}


2、File对象功能

File类常见方法:

1.创建

       booleancreateNewFile():在制定位置创建文件,如果该文件已经存在,则不创建,返回false;和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,均会覆盖文件。

       booleanmkdir():创建文件夹

       booleanmkdirs():创建多级文件夹

2.删除

       booleandelete():删除失败,返回false

       voiddeleteOnExit():在程序退出的时候删除指定文件。

3.判断

       booleanexists():文件是否存在

       isFile():判断是否是文件

       isDirectory():判断是否是目录

       isHidden():判断是否隐藏,Java一般最好不要访问隐藏文件,否则会出错

       isAbsolute():是否是绝对路径 

4.获取信息

       getName();获取文件或目录名称

       getPath();获取路径

       getParent();获取父目录

       getAbsolute();获取绝对路径

       longlastModified();最后修改时间

       longlength();获取文件大小

class FileDemo
{
public static void main(String[] args) throws IOException
{
method_5();
}

publicstatic void method_5()
{
File f1 = new File("C:\\1.log");
File f2 = new File("C:\\2.txt");
sop("fename:"+f1.renameTo(f2));//重命名,类似于Windows下的剪切
}

public static void method_4()
{
File f = new File("file.txt");

sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());
sop("parent:"+f.getParent());//该方法返回的是绝对路径中的父目录,如果获取的是相对路径,返回null。
//如果相对路径中有上一层目录,那么该目录就是返回结果。
}
public static void method_3()
{
File f = new File("file.txt");
//f.createNewFile();
f.mkdir();

//记住,在判断文件对象是否是文件或者目录时,必须要先判断该文件对象封装的内容是否存在。
//通过exists来判断。

sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());
}
public static void method_2()
{
File f = new File("file.txt");
//创建文件夹
File dir = newFile("abc\\a\\c\\c\\v\\v\\n\\f\\r");

//sop("mkdir:"+dir.mkdirs());
sop("delete:"+dir.delete());
}
public static void method_1()throws IOException
{
File f = new File("file.txt");
f.deleteOnExit();//程序在退出的时候将垃圾文件删除
//sop("create:"+f.createNewFile());
sop("delete:"+f.delete());
//如果想删除一个文件,但文件正在被使用,放在finally里面仍旧删不掉
}
}


3、File对象功能-文件列表

import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
listDemo_3();
}

public static void listDemo_3()
{
File dir = new File("D:\\java0414\\day18");
File[] files = dir.listFiles();

for(File f:files)
sop(f.getName()+"......"+f.length());
}
public static void listDemo_2()
{
File dir = new File("D:\\java0414\\day18");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
//sop("dir:"+dir+"......name::"+name);
/*
if(name.endsWith(".bmp"))
returntrue;
return false;
*/
return name.endsWith(".java");
}
});
sop("len:"+arr.length);
for(String name:arr)
{
sop(name);
}
}
public static void listDemo()
{
File f = new File("C:\\");
String[] names = f.list();//调用list方法的file对象必须是封装了一个目录。该目录还必须存在。
for(String name:names)
sop(name);
}
public static void listRootDemo()
{
File[] files = File.listRoots();//获取系统有效盘符
for(File f:files)
{
sop(f);
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}


4、列出目录下所有内容—递归

因为目录中还有目录,只要使用同一个列出目录功能的桉树完成即可。

在列出过程中出现的还是目录的话,还可以再次调用本功能。

也就是函数自身调用自身。

这种表现形式,或者编程手法,称为递归。

import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("D:\\java0414");
showDir_1(dir);
//showDir(dir);

//toBin(6);
//int n = getSum(10);
//System.out.println("n="+n);
}
public static int getSum(int n)
{
if(n==1)
return1;
return n+getSum(n-1);
}
public static void toBin(int num)
{
while(num>0)
{
System.out.println(num%2);
num= num/2;
}
}

public static void showDir(File dir)
{
System.out.println(dir);//显示根目录
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)
{
if(files[x].isDirectory())
showDir(files[x]);
else
System.out.println(files[x]);
}
}
}
小结:

递归要注意:

1.限定条件。

2.要注意递归的次数,尽量避免内存溢出。

/*

showA(); -->CBA

void showA()

{

       showB();

       showA();

}

void showB()

{

       showC();

       showB();

}

void showC()

{

       showC();

}

*/

 

5、删除一个带内容的目录

删除原理:

在Windows中,删除目录从里面往外删除的。

既然是从里往外删除,就需要用到递归。

import java.io.*;
class RemoveDir
{
public static void main(String[] args)
{
File dir = newFile("D:\\javatest");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files = dir.listFile();
for(int x=0;x<files.length; x++)
{
if(!files.isHidden()&& files[x].idDirectory())
removeDir(files[x]);
else//之所以输出是为了更方便的了解文件是否删除
System.out.println(files[x].toString()+"::::"+files[x].delete());
}
System.out.println(dir+"::dir::"+dir.delete());
}
}
小结:

Java是无法删除带隐藏属性的文件,因此需要删除某个文件前,最好能判断文件是否隐藏,且Java删除文件时不走回收站,因此在确保文件的确要删除的前提下,再进行删除动作。

 

6、创建Java文件列表

练习:

将制定目录下的java文件的绝对路径,存储到一个文本文件中,

建立一个java文件列表文件。

思路:

1.对制定的目录进行递归。

2.获取递归过程中所有java文件的路径

3.将这些路径存储到集合中。

4.将集合中的数据写入到一个文件中。

import java.io.*;
import java.util.*;
class JavaFileList
{
public static void main(String[] args) throws IOException
{
File dir = new File("E:\\黑马程序员JavaEE+Android——开学前自学的Java课程");

List<File> list = new ArrayList<File>();

fileToList(dir,list);
//System.out.println(list.size());

File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();

for(File file:files)
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".avi"))
list.add(file);
}

}
}

public static void writeToFile(List<File> list,String javaListFile)throws IOException
{
BufferedWriter bufw = null;
try
{
bufw= new BufferedWriter(new FileWriter(javaListFile));
for(Filef:list)
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw e;
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch(IOException e)
{
throw e;
}
}
}
}


7、IO流—Properties

1.简述

Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。是集合中和IO技术相结合的集合容器。该对象特点:可以用于键值对形式的配置文件。

2.Properties存取

Set<String>stringPropertyNames()  返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键

import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args)
{
setAndGet();
}
public static void setAndGet()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","39");

//System.out.println(prop);

String value =prop.getProperty("lisi");
//System.out.println(value);

prop.setProperty("lisi","89");
Set<String> names =prop.stringPropertyNames();
for(String s : names)
{
System.out.println(s+":"+prop.getProperty(s));
}
}
}


8、Properties存取配置文件

Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。

是集合中和IO技术相结合的容器。

该对象的特点:可以用于键值对形式的配置文件。

那么在加载数据时,需要数据有固定格式:键=值

void load(InputStream inStream)  从输入流中读取属性列表(键和元素对)

void load(Readr reader)  按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)

void list(PrintStream out)  将属性列表输出到制定的输出流

void list(PrintWriter out)  将属性列表输出到制定的输出流

void store(Writer writer,String comments)   以适合使用load(Reader)方法的格式,将此Properties表中的属性列表(键和元素对)写入输出字符。

import java.io.*;
import java.util.*;
class PropertiesDemo2
{
public static void main(String[] args) throws IOException
{
//method_1();
loadDemo();
}
public static void loadDemo()throws IOException
{
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//将流中的数据加载进集合
prop.load(fis);

prop.setProperty("wangwu","39");
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos,"haha");

//System.out.println(prop);
prop.list(System.out);

fos.close();
fis.close();
}

 /*
演示,如何将流中的数据存储到集合中。
想要将info.txt中键值数据存到集合中进行操作。

1.用一个流和info.txt文件关联。
2.读取一行数据,将改行数据用“=”进行切割
3.等号左边作为键,右边作为值,存入到Properties集合中即可
*/
public static void method_1()throws IOException
{
BufferedReader bufr =
new BufferedReader(new FileReader("info.txt"));

String line = null;
Properties prop = new Properties();
while((line=bufr.readLine())!=null)
{
String[]arr = line.split("=");
//System.out.println(arr[0]+"..."+arr[1]);
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
public static void SetAndGet()
{
Properties prop = new Properties();

prop.setProperty("zhangsan","30");
prop.setProperty("lisi","39");

//System.out.println(prop);
String value =prop.getProperty("lisi");
//System.out.println(value);

prop.setProperty("lisi","89");
Set<String> names =prop.stringPropertyNames();
for(String s : names)
{
System.out.println(s+"::"+prop.getProperty(s));
}
}
}

小结:

load只是将数据写入到流中,而store则是将数据写入到流以后,并写入到文件中。

凡是前面带#表示注释信息,不会被Properties所加载,前提是Properties所加载的必须是键值对


练习:

用于记录应用程序运行次数,如果使用次数一道,那么给出注册提示。

很容易想到的是:计数器,可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。

可是随着该应用程序的退出,该计数器也在内存中消失了。下一次在启动该程序,又重新开始从0计数。这样不是我们想要的。

程序及时结束,该计数器的值也存在。下次程序启动在会先加载该计数器的值并加1后在重新存储起来。

所以要建立一个配置文件,用于记录该软加你的使用次数。该配置文件使用键值对的形式,这样便于阅读数据,并操作数据。

键值对数据时map集合,数据时一文件的形式存储,使用IO技术,那么map+io -->Properties。配置文件可以实现应用程序数据的共享。

import java.io.*;
import java.util.*;
class RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();

File file = new File("count.ini");
if(!file.exists())
file.createNewFile();

FileInputStream fis = new FileInputStream(file);
prop.load(fis);

int count = 0;
String value =prop.getProperty("time");

if(value !=null)
{
count= Integer.parseInt(value);
if(count>=5)
{
System.out.println("您好,该软件使用次数已到,请注册!");
return ;
}
}
count++;
prop.setProperty("time",count+"");

FileOutputStream fos = newFileOutputStream(file);
prop.store(fos,"");

fos.close();
fis.close();
}
}
小结:

将文件封装成对象,方便对文件的操作,例如可以判断文件是否存在,然而流却无法直接对文件进行该操作。

 

9、IO包中的其他类

打印流:PrintWriter与PrintStream,可以直接操作输入流和文件。该流提供了打印方法,可以将各种数据类型的数据都能打印。

1、字节打印流:PrintStream

构造函数可以接收的参数类型:

1.file对象,File;

2.字符串路径,String;

3.字节输出流,OutputStream

 

2、字符打印流:PrintWriter

构造函数可以接收的参数类型:

1.file对象,File;

2.字符串路径,String;

3.字节输出流,OutputStream

4.字符输出流,Writer

public PrintWriter(OutputStream out,booleanautoFlush)    通过现有的OutputStreamWriter创建新的PrintWriter。

out:输出流   autoFlush:boolean变量,如果为true,则println、printf或format方法将刷新输出缓冲区

import java.io.*;
class PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
//输入流
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//输出流
//PrintWriter out = new PrintWriter(System.out,true);//添加true后可直接自动刷新
PrintWriter out = new PrintWriter(newFileWriter("a.txt"),true);//如果想直接写入到文件里,可以先将文件封装成流对象,然后进行true自动刷新,保证数据安全
//如果想提高效率,则也可以嵌套BufferedWriter
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
//out.write(line.toUpperCase());//既然是打印流,那么可以直接用println进行换行
out.println(line.toUpperCase());
//out.flush();
}
out.close();
bufr.close();
}
}
小结:

需要特别注意的一点是,如果PrintWriter中带true方法,那么输出到控制台中的println必须加ln,否则无法正常识别并换行

 

10、合并流

序列流:SequenceInputStream,对多个流进行合并。

SequenceInputStream

public SequenceInputStream(Enumeration<?extends InputStream> e)通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。将按顺序读取由该枚举生成的输入流,以提供从此 SequenceInputStream 读取的字节。在用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。

import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
//由于SequenceInputStream中如果需要合并多个对象的时候,就需要Enumeration,而只有Vector中才有Enumeration对象,于是就事先创建Vector带泛型的对象
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("C:\\1.txt"));
v.add(new FileInputStream("C:\\2.txt"));
v.add(new FileInputStream("C:\\3.txt"));

Enumeration<FileInputStream> en =v.elements();

SequenceInputStream sis = new SequenceInputStream(en);

FileOutputStream fos = new FileOutputStream("C:\\4.txt");

byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}


11、切割文件

import java.io.*;
import java.util.*;

class SplitFile
{
public static void main(String[] args) throws IOException
{
//splitFile();
hebing();
}
//合并对象
public static void hebing()throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<=7; x++)
{
al.add(new FileInputStream("C:\\splitfiles\\"+x+".part"));
}
//由于内部类访问的是本地变量,因此这里的迭代器必须被final修饰
final Iterator<FileInputStream> it= al.iterator();
Enumeration<FileInputStream> en =new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);

FileOutputStream fos = new FileOutputStream("C:\\splitfiles\\1.exe");

byte[] buf = new byte[1024];
int len =0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}

//切割文件
public static void splitFile()throws IOException
{
FileInputStream fis = new FileInputStream("C:\\BaiduYun_3.6.0.exe");

FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];

int len =0;
int count = 1;
while((len=fis.read(buf))!=-1)
{
fos= new FileOutputStream("C:\\splitfiles\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}

小结:

在定义切割容器的读取容器byte大小时,不能直接将其定义得超过一定大小,否则会发生内存溢出异常,因此这里可以再次定义一个容器,达到一定数据大小后,将定义好的输出流对象写入相关数据文件中,依次就能将一个较大文件切割完毕,既提高了效率,又防止内存溢出。


---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net