File类
管道流
File类
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数
了解file类中的常用方法。
separator(跨平台的目录分隔符==\\)与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
File类常见方法:
1,创建
boolean creatNewFile();在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
static File createTempFile(String prefix,String suffix)在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
static File createTempFile(String prefix,String suffix,File directory)在指定文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,会覆盖
boolean mkdir();创建文件夹
boolean mkdirs();创建多级文件夹
2,删除
boolean delete():删除失败返回false
void deleteOnExit();在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。在程序退出时删除指定文件
3,判断
boolean compareTo(File pathname)按字母顺序比较两个抽象路径名。
boolean exists():文件是否存在
isfile();测试此抽象路径名表示的文件是否是一个标准文件。
isDirectory();测试此抽象路径名表示的文件是否是一个目录
isHidden();/测试此文件是否是一个隐藏文件。
isAbsolute();测试此抽象路径名是否为绝对路径名。
4,获取信息
getName();获取名称
getPath()将此抽象路径名转换为一个路径名字符串。
getParent();返回此抽象路径名父目录的路径名字符串,如果此路径名没有指定父目录,则返回null.
getParentFile()返回此抽象路径名父目录的抽象路径名,如果此路径名没有指定父目录,则返回null.
getAbsolutePath();返回的是绝对路径名字符串
getAbsoluteFile();返回绝对路径名形式
long length()返回由此抽象路径名表示的文件的长度。
long lastModified() 返回最后一次被修改的时间。
示例:
import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException
{ method_2();
method_1();
consMethod();
}
public static void method_5()throws IOException
{
File f=new File("c:\\text.java");
File f1=new File("d:\\haha.java");
System.out.println("rename:"+f.renameTo(f1));//将f的名称换成f1的。
}
public static void method_4()throws IOException
{
File f=new File("d:\\abc\\file1.txt");
System.out.println("path:"+f.getPath());//封装什么就是什么
System.out.println("abspath"+f.getAbsolutePath());//不论是什么都是绝对的。
System.out.println("parent"+f.getParent());//该方法返回的是绝对路径中的父目录,如果获取的是相当路径,返回的是null
//如果相对路径中有上一层目录,那么该目录返回结果。
}
public static void method_3() throws IOException
{
File f=new File("file.txt");
//f.createNewFile();结果是文件是真,目录是假
f.mkdir();//结果是目录是真,文件是假。
//记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在
//通过exists判断
System.out.println("dir:"+f.isDirectory());
System.out.println("file:"+f.isFile());
System.out.println(f.isAbsolute());//绝对路径的判断
}
public static void method_2()
{
File f=new File("file.txt");
//System.out.println("exists:"+f.exists());
//创建文件夹
File dir=new File("abc\\kkk");
System.out.println("mkdir:"+dir.mkdir());
//System.out.println("execute"+f.canExecute());测试应用程序是否可以执行此抽象路径名表示的文件。
}
public static void method_1() throws IOException
{
File f=new File("file.txt");
f.deleteOnExit();
//code();
System.out.println("creat:"+f.createNewFile());
System.out.println("delete:"+f.delete());
}
//创建File对象
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");
System.out.println("f1:"+f1);
System.out.println("f2:"+f2);
System.out.println("f3:"+f3);
File f4=new File("c:"+File.separator/*\\目录分隔符*/+"abc\\zzz\\a.txt");
}
}
List
static File listRoots():列出可用的文件系统根,
String[]list(FilenameFilter filter):返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录
list():返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File[] listFiles(FileFilter filter):返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles(FilenameFilter filter):返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
FilenameFilter:接口,实现此接口的类实例可用于过滤器文件名
boolean accept(File dir,String name):测试指定文件是否应该包含在某一文件列表中。
示例:
import java.io.*;
public class FileDemo2 {
public static void main(String[] args) {
File dir=new File("c:\\");
File[] files=dir.listFiles();
for(File f:files)
{
System.out.println(f.getName()+"::"+f.length());
}
listDemo();
listRootsDemo();
}
public static void listDemo_2()
{
File dir=new File("d:javabiji18");
String[]arr=dir.list(new FilenameFilter()
{
public boolean accept(File dir/*要过滤的名称*/,String name)
{ /*System.out.println("dir:"+dir+"...name::"+name);
if(name.endsWith(".bmp"))
return true;
else
return false;*/
return name.endsWith(".bmp");
}
});//匿名对象类。
System.out.println("len:"+arr.length);
for(String name:arr)
{
System.out.println(name);
}
}
public static void listDemo()
{
File f=new File("c:\\");
String[] names=f.list();//打印C盘下的所有文件,调用list方法的file对象必须是封装了一个目录,该目录还必须存在。否则抛出异常。当前的文件和文文件夹的名称。包含隐藏文件。
for(String name:names)
{
System.out.println(name);
}
}
public static void listRootsDemo()
{
File[] files =File.listRoots();
for(File f:files)
{
System.out.println(f);
}
}
}
列出指定目录下文件或者文件夹,包含子目录中的内容,也就是列出指定目录下所有内容,因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。在列出过程中出现的还是目录的话,还可以再次调用本功能。也就是函数自身调用自身,这种表现形式,或者编程手法,称为递归。
递归要注意:
1,限定条件,
2,要注意递归的次数,尽量避免内存溢出。
import java.io.*;
public class FileDemo3 {
public static void main(String[] args) {
File dir=new File("d:\\java123");
showDir(dir,0);
/* toBin(6);
int n=getSum(10);
System.out.println("n:"+n);*/
}
public static String getLevel(int level)
{
StringBuilder sb=new StringBuilder();
sb.append("|--");
for(int x=0;x<level;x++)
{
//sb.append("!===");
sb.insert(0, "!--");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files=dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(files[x].isDirectory())
showDir(files[x],level);
else
System.out.println(files[x]);
}
}
/* public static int getSum(int n)
{ if(n==1)
return 1;
return n+getSum(n-1);
}
public static void toBin(int num)
{
if(num>2)
{
toBin(num/2);
System.out.println(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]);
}
}*/
}
/*void showA()
{
System.out.println(A);
}
void showB()
{
System.out.println(B);
}
void showC()
{
System.out.println(C);
}
*/
删除一个带内容的目录
删除原理:在window中,删除目录从里面往外删除的,既然是从里往外删除,就需要用到递归。java删除是不走回车站的。
import java.io.*;
public class RemoveDir {
public static void main(String[] args) {
File dir=new File("d:\\testdir");
removeDir(dir);
}
public static void removeDir(File dir)
{ // if(dir.exists())
File[] files=dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(/*!files[x].isHidden()不是隐藏的&&*/files[x].isDirectory())
removeDir(files[x]);
//else
System.out.println(files[x].toString()+":file:"+files[x].delete());
}
System.out.println(dir+"::dir::"+dir.delete());
}
}
练习 :将一个指定目录下的java文件的绝对路径,存储到一个文本文件中,建立一个java文件列表文件
思路:
1,对指定的目录进行递归
2,获取递归过程所有的java文件的路径
3,将这些路径存储到集合中。
4,将集合中的数据写入到一个文件中。
import java.io.*;
import java.util.*;
public class JavaFileList {
public static void main(String[] args) {
File dir=new File("d:\\java123");
List<File>list=new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file=new File(dir,"javalist.txt");
writerToFile(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(".java"))
list.add(file);
}
}
}
public static void writerToFile(List<File>list,String javaListFile)
{
BufferedWriter bufw=null;
try {
bufw = new BufferedWriter(new FileWriter(javaListFile));
for (File f : list) {
String path = f.getAbsolutePath();
bufw.write(path);
}
} catch (IOException e) {
throw new RuntimeException();
}
finally{
try {
if(bufw!=null)
bufw.close();
} catch (Exception e2) {
throw new RuntimeException();
}
}
}
}
Properties是hashtable的子类, 也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,不需要泛型。
是集合中和io技术相符合的集合容器
该对象的特点可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值,必须有键和值。
void load(InputStream inStream)从输入流中读取属性列表(键和元素对)
void load(Reader reader)按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
void loadFromXML(InputStream in)将指定输入流中由XML文档所表示的所有属性加载到此属性表中。
Object setProperty(String key,String value)调用Hashtable的方法put。
void store(OutputStream out,String connents)以适合使用load(InputStream)方法加载到Properties表中的格式,将此Properties表中的属性列表(键和元素对)写入输出流。
void store(Writer writer,String connents)以适合使用load(Reader)方法的格式,将此Properties表中的属性列表(键和元素对)写入输出字符。
void storeToXML(OutputStream out,Stringconnents)发出一个表示此表中包含的所有属性的XML文档
void storeToXML(OutputStream out,Stringconnents,String encoding)使用指定的编码发出一个表示此表中包含的所有属性的XML文档。
Set(String) stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串,如果是在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
import java.io.*;
import java.util.*;
public class PropertiesDemo {
public static void main(String[] args) throws IOException
{ loadDemo();
//method_1();
//setAndGet();
}
//load方法原理。
public static void loadDemo() throws IOException
{
Properties prop=new Properties();
FileInputStream fis=new FileInputStream("info.txt");//先关联一个文件。
//将流中的数据加载进集合
prop.load(fis);
prop.setProperty("wangwu", "34");//改变内存的方法,操作集合中的数据.Property加载的是键值对。
FileOutputStream fos=new FileOutputStream("info.txt");
prop.store(fos, "hah");
//System.out.println(prop);
prop.list(System.out);//列出来
fos.close();
fis.close();
}
/*
* 演示,如何将流中的数据存储到集合中
* 想要将info.txt中键值数据存到集合中进行操作
* 1,用一个流和info.txt文件关联
* 2,读取一行数据,将该行数据用”=“进行切割
* 3,等号左边作为键,右边作为值,存入到properties集合中即可
* split切割。
* */
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","32");//设置键值对。
prop.setProperty("lisi", "34");
System.out.println(prop);
String value=prop.getProperty("lisi");
System.out.println(value);
prop.getProperty("lisi",98+"");
Set<String> names=prop.stringPropertyNames();
for(String s:names)
{
System.out.println(s+":"+prop.getProperty(s));
}
}
}
用于记录应用程序运行次数,如果使用次数已到,那么给出注册提示。很容易想到的是计数器,可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增,可是随着该应用程序的退出。
该计数器也在内存中消失了,下一次在启动该程序,又重新开始从0计数。这样不是我们想要的,
程序即使结束,该计数器的值也存在,
下次程序启动会先加载该计数器的值并加1后在重新存储起来,
所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。这样便于阅读数据,并操作数据。
键值对数据是map集合。数据是以文件形式存储,使用io技术那么map+io->properties,配置文件可以实现应用程序数据的共享。
如何创建配置文件,如何使用配置文件。
有限,数据关系不能太复杂,
Document接口,表示整个HTML或XML文档,从概念上讲,它是文档树的根,并提供对文档数据的基本访问。
java拿这些数据很麻烦。因此有dom4j (dom for java。)工具来完成。
import java.util.*;
import java.io.*;
public 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");//time键获取值。
if(value!=null)
{count=Integer.parseInt(value);//count记录次数。
if(count>=5)
{
System.out.println("你好,使用次数已到");
return;
}
}
count++;
prop.setProperty("time", count+"");
FileOutputStream fos=new FileOutputStream(file);//写回去。
prop.store(fos, "");//注册信息。
fos.close();
fis.close();
}
}
//dom4j dom for java
打印流
PrintWriter 与PrintStream可以直接操作输入流和文件
该流提供了println()打印方法,可以将各种数据类型的数据都原样打印
字节打印流
PrintStream,构造函数可以接收的参数类型
1,file对象 File
2,字符串路径,String
3,字节输出流,OutputStream
字符打印流
PrintWriter,构造函数可以接收的参数类型
1,File对象File
2,字符串路径String
3,字节输出流OutputStream
4,字符输出流,Writer
PrintWriter(OutputStream out,boolean autoFlush)通过现有的OutputStream创建新的PrintWriter.
autoFlush -boolean变量:如果为true,则println,printf或format方法将刷新输出缓冲区。
void println():保证数据原样性将数据打印出来。
import java.io.*;
public 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);
PrintWriter out=new PrintWriter(new FileWriter("a.txt"),true);//可以将文件放到流里面。
String line=null;
while((line=bufr.readLine())!=null)
{ if("over".equals(line))
break;
//out.write(line.toUpperCase());
out.println(line.toUpperCase());//没有ln是不能刷新的。刷新只对流而言的,
//out.flush();
}
out.close();
bufr.close();
}
}
IO包中的其他类
序列流: SequenceInputStream,对多个流进行合并
操作对象
ObjectInputStream与 ObjectOutputStream被操作的对象需要实现Serializable(标记接口)
SequenceInputStream 表示其他输入流的逻辑串联,它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。多个文件合并成一个文件。
练习:文件分割程序。
import java.io.*;
import java.util.*;
public class SequenceDemo {
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v=new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.tdt"));
v.add(new FileInputStream("c:\\2.tdt"));
v.add(new FileInputStream("c:\\3.tdt"));
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();
}
}
切割文件
import java.util.*;
import java.io.*;
public class splitFile {
public static void main(String[] args)throws IOException
{ merge();
// splitFile();
}
public static void merge() throws IOException
{ ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
for(int x=1;x<=3;x++)
{
al.add(new FileInputStream("c:\\splitfiles\\"+x+".part"));
}
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\\0.jpg");
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:\\1.jpg");//关联文件
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();
}
}
管道流:管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。
注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。
public static void main(String[] args) throws IOException{
PipedInputStream pipin = new PipedInputStream();
PipedOutputStream pipout = new PipedOutputStream();
pipin.connect(pipout);
new Thread(new Input(pipin)).start();
new Thread(new Output(pipout)).start();
}
对象的序列化:目的:将一个具体的对象进行持久化,写入到硬盘上。
注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
如何将非静态的数据不进行序列化?用transient 关键字修饰此变量即可。
Serializable:用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object obj = ois.readObject();//读取一个对象。
System.out.println(obj.toString());
}
public static void writeObj()throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",25)); //写入一个对象。
oos.close();
}
}
class Person implements Serializable{
private static final long serialVersionUID = 42L;
private transientString name;//用transient修饰后name将不会进行序列化
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"::"+age;
}
}
-----------------------------------------------------------------------------------------------
DataOutputStream、DataInputStream:专门用于操作基本数据类型数据的对象。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(256);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
System.out.println(num);
dis.close();
-----------------------------------------------------------------------------------------------
ByteArrayInputStream:源:内存
ByteArrayOutputStream:目的:内存。
这两个流对象不涉及底层资源调用,操作的都是内存中数组,所以不需要关闭。
直接操作字节数组就可以了,为什么还要把数组封装到流对象中呢?因为数组本身没有方法,只有一个length属性。为了便于数组的操作,将数组进行封装,对外提供方法操作数组中的元素。
对于数组元素操作无非两种操作:设置(写)和获取(读),而这两操作正好对应流的读写操作。这两个对象就是使用了流的读写思想来操作数组。
//创建源:
ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
//创建目的:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());
--------------------------------------------