黑马程序员_毕向东_Java基础_DAY20-21_File、Properties、各种功能流

时间:2023-02-11 12:55:08

----------- android培训java培训、期待与您交流! ------------

File类

文件是一类事物,它有自己的名字、属性、大小、位置、后缀名等属性信息,那么根据面向对象的思想,就可以把它封装描述为一个类,

这个类就java.io包中的File类。File类是文件和目录路径名的抽象表示形式,它可以方便的对文件与文件夹的属性信息进行操作,也可以作为参数传递给流对象。

它弥补了了流的不足,比如流只能操作数据,而不能操作文件的属性与文件夹。

 

java.lang.Object

 java.io.File

文件和目录路径名的抽象表示形式。

 

构造方法摘要

File(File parent, String child)

File(String pathname)

File(String parent, String child)

File(URI uri) 

 

//将存在或不存在的文件或文件夹封装成对象

File f1 = newFile("filedemo.txt");

//将目录和文件名分开存放

File f2 = newFile("c:\\bi\\day20", "filedemo2.txt");

 

//目录可以用File表示

File d1 = newFile("c:\\bi\\day20");

File f3 = new File(d1,"filedemo3.txt"); //将File传入构造器

 

File.toString()返回的是文件的路径,封装的是什么,返回的就是什么。如果封装的是相对路径,返回的也是相对路径。

 

关于目录分割符:

windows使用\作为目录分割符,/也可以用。

linux系统使用/作为分割符。

 

因为各个平台的目录分割符不统一,所以使用"c:\\bi"这种形式的定义方式不具备跨平台性,此时可以使用File文件的静态字段separator来标示一个与系统有关的默认名称分隔符。

static String separator

static char separatorChar

 

File类常用方法:

1.创建:

boolean createNewFile()

 

File f = new File("file.txt");

sop("create: " +f.createNewFile());

 

在指定位置创建文件,如果该文件已经存在,则不创建返回false。

如果文件不存在,则创建空文件,返回true。

 

注意:这里和输出流不一样,输出流与文件关联后,如果文件不存在直接创建文件,如果文件存在,则覆盖原文件。

 

//创建在默认临时文件目录中

static File createTempFile(String 前缀,String 后缀)

//创建在指定目录中

static File createTempFile(String 前缀,String 后缀, Filedirectory)

 

创建文件夹:

 boolean mkdir() //直接创建目录

 boolean mkdirs() //如果创建此目录所需的父目录不存在,则依次创建

 

2.删除:

boolean delete() //删除

void deleteOnExit() //在退出时删除

 

3.判断:

 boolean exists()

 boolean isDirectory()

 boolean isFile()

 boolean isHidden()

 boolean canExecute()  //文件是否可执行

 boolean canRead()

 boolean canWrite()

 boolean isAbsolute()

 

 boolean equals(Object obj)

 intcompareTo(File pathname)

 

进行isDirectory和isFile判断之前,一定要先进行exists判断。

 

4.获取:

getName()

getParent() //返回指明了的父目录,如果未指明,返回null

getPath()

getAbsolutePath()

lastModified()

length() //目录的大小为0

 

String[] list()

String[] list(FilenameFilter filter)

File[] listFiles()

File[] ListFiles(FileFilter filter)

File[] ListFiles(FilenameFilter filter)

File[] listRoots()

 

5.重命名

boolean renameTo(File dest)

重命名操作无法将一个文件从一个文件系统移动到另一个文件系统

 

练习:

class FileDemo 
{
public static void main(String[] args) throws IOException
{
method_4();
}
public static void method_4() throws IOException
{
File f1 = new File("c:\\Test.java");
File f2 = new File("c:\\haha.java");

System.out.println("rename:"+f1.renameTo(f2));//类似剪切,并修改文件名
}
public static void method_3() throws IOException
{
File f = new File("FileDemo.java");

System.out.println("path:"+f.length());
System.out.println("path:"+f.getAbsolutePath());

}
public static void method_2() throws IOException
{
File f = new File("file.txt");
f.mkdir();
//在判断文件对象是否是文件或者目录时,必须先判断该文件是否存在.
//通过exists()判断.
System.out.println("dir:"+f.isDirectory());
System.out.println("dir:"+f.isFile());
}
public static void method_1() throws IOException
{
File f = new File("file.txt");
System.out.println("create:"+f.createNewFile());//创建
System.out.println("delete:"+f.delete());//删除
System.out.println("execute:"+f.canExecute());//判断是否能执行
System.out.println("exist:"+f.exists());//判断文件是否存在
}

//创建File对象
public static void consMethod()
{
//将a.txt封装成file对象.可以将已有的和未出现的文件或者文件夹封装成对象.
File f1 = new File("c:\\abc\\a.txt");

//File.separator跨平台的分隔符类似newLine()
File f2 = new File("c:"+File.separator+"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);
}
}

 
class FileDemo2 
{
public static void main(String[] args)
{
listFileDemo();
}
public static void listFileDemo()
{
File dir = new File("d:\\learn\\day19");
//获取当前目录下所有文件的对象.
File[] files = dir.listFiles();
for (File f : files )
{
System.out.println(f.getName()+"::"+f.length());
}
}
public static void listDemo()
{
File f = new File("D:\\learn\\day19");
//调用list方法的file对象封装的必须是一个目录,并且存在.
String[] names = f.list(new MyFilenameFileter());//传进一个过滤器
for(String s : names)
{
System.out.println(s);
}
}

public static void listRootsDemo()
{
//列出电脑中有效的盘符
File[] files = File.listRoots();

for(File f : files)
{
System.out.println(f);
}
}
}

//定义一个过滤器
class MyFilenameFileter implementsFilenameFilter
{
public boolean accept(File dir,String name)
{
return name.endsWith(".class");
}
}

递归--列出目录下所有内容:

/*
列出指定目录下文件或者文件夹,包含子目录中的内容.
也就是列出指定目录下所有内容.

因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可.
在列出过程中出现的还是目录的话,还可以再次调用本功能.
也就是函数自身调用自身.
这种表现形式,或者变成手法,称为递归.

递归要注意的:

1.一定要限定条件

2.要注意递归的次数,尽量避免内存溢出.
*/
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File f = new File("d:\\learn");
//showDir(f);
//toBin(6);
System.out.println(getSum(10));
}
public static int getSum(int n)
{
if (n==1)
return 1;
else
return n+getSum(n-1);

}
public static void toBin(int n)
{
if (n>0)
{
toBin(n/2);
System.out.print(n%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]);
}
}
}

列出目录下所有内容--带层级 

import java.io.*; 
class FileDemo4
{
public static void main(String[] args)
{
File f = new File("d:\\learn");
showDir(f,0);
}
//定义一个层级方法
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
for (int x = 1; x<level; x++)
{
sb.append(" ");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir);
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(getLevel(level)+files[x]);
}
}
}

 

删除带内容的目录

import java.io.*; 
/*
删除原理:
在windows中,删除目录是从里面往外删除的.

既然是从里面往外删除,就需要用到递归.
*/
class RemoveDir
{
public static void main(String[] args)
{
File dir = new File("d:\\新建文件夹");
removeDir(dir);
}

public static void removeDir(File dir)
{
File [] files = dir.listFiles();
for (int x=0; x<files.length; x++ )
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x]+"--file--"+files[x].delete());
}
System.out.println(dir+"==dir=="+dir.delete());
}
}

 

创建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("d:\\learn");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
File file = new File(dir,"javalist.txt");
writeTOFile(list,file);
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();
for (File f : files )
{
if (f.isDirectory())
fileToList(f,list);
else
{
if(f.getName().endsWith(".java"));
list.add(f);
}
}
}
public static void writeTOFile(List<File> list,File file)throwsIOException
{
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
for (File f : list )
{
bw.write(f.getAbsolutePath());
bw.newLine();
bw.flush();
}
}
}

Properties类

Properties是hashtable的子类.

也就是说它具备map集合的特点.而且它里面存储的键值对都是字符串.

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

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

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

import java.io.*; 
import java.util.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
//setAndget();
//method_1();
loadDemo();
}
//Properties中提供了load方法来完成method_1
public static void loadDemo() throws IOException
{
Properties prop = new Properties();
FileInputStream fis = newFileInputStream("c:\\info.txt");
prop.load(fis);
prop.setProperty("zhangsan","88");
FileOutputStream fos = newFileOutputStream("c:\\info.txt");
prop.store(fos,"haha");
prop.list(System.out);
fis.close();
fos.close();
}

//演示,如何将流中的数据存储到集合中.
//想要将info.txt中键值数据存到集合中进行操作.
/*
1.用一个流和info.txt文件关联.
2.读取一个数据,将该数据用"="进行切割
3.等号左面作为键,右边作为值.存入到Properties集合中即可
*/
public static void method_1() throws IOException
{
BufferedReader br = new BufferedReader(newFileReader("c:\\info.txt"));
Properties prop = new Properties();
String line = null;
while ((line=br.readLine())!=null)
{
String[] arr = line.split("=");
prop.setProperty(arr[0],arr[1]);
}
br.close();
System.out.println(prop);
}

//设置和获取元素.
public static void setAndget()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","39");
prop.setProperty("lisi","47");

System.out.println(prop);
System.out.println(prop.getProperty("lisi"));

prop.setProperty("lisi",90+"");

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

}
}

 

Properties练习--限定程序执行次数

import java.io.*; 
import java.util.*;
/*
用于记录应用程序运行次数.
如果使用次数已到,那么给出注册提示.

很容易想到的是:计数器.
开始该计数器定义在程序中,随着程序的运行而存在的内存中,并进行字增
可是随着该应用程序的推出,该计数器也在内存中消失了.

下一次在启动该程序,又重新开始从0计数
这样就不是我们想要的.

程序即使结束,该计数器的值也存在.
下次程序启动会先家在该计数器的值并加1后在重新存储起来.

所以要建立一个配置文件,用于记录该软件的使用次数.

该配置文件使用键值对的形式.
这样便于阅读数据,并操作数据.

键值对数据是map集合
数据是以文件形式存储,用到IO技术.
那么map-->Properties + IO

配置文件可以实现应用程序数据的共享.

1.创建有给读取流关联配置文件
*/
class RunCount
{
public static void main(String[] args) throws IOException
{
File file = new File("c:\\property.ini");
if(!file.exists())
file.createNewFile();
Properties prop = new Properties();
FileInputStream fr = new FileInputStream(file);
prop.load(fr);
String value = prop.getProperty("count");
if(value==null)
prop.put("count","1");
else
{
System.out.println(value);
int count = Integer.parseInt(value);
if(count>=5)
{
System.out.println("您的使用次数已到");
return;
}
count++;
prop.setProperty("count",count+"");
}
FileOutputStream fw = new FileOutputStream(file);//输出流会覆盖原文件
prop.store(fw,"test");
fr.close();
fw.close();
}
}

打印流PrintWriter和PrintStream

打印流:

该流提供了打印方法,可以将各种数据类型的数据都原样打印.

字节打印流

PrintStream

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

1.File对象.File

2.字符串路径.String

3.字节输出流.OutputStream

字符打印流

PrintWriter(常用)

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

1.File对象.File

2.字符串路径.String

3.字节输出流.OutputStream

4.字符输出流.Writer

import java.io.*; 

class PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
BufferedReader br =
new BufferedReader(newInputStreamReader(System.in));
PrintWriter pw =
new PrintWriter(newFileWriter("c:\\demo.txt"),true);//可实现自动刷新
String line = null;
while ((line=br.readLine())!=null)
{
if(line.equals("over"))
break;
pw.println(line.toUpperCase());
}
br.close();
pw.close();
}
}

序列合并流

SequenceInputStream是能对多个流进行合并成一个读取流,它在构造时需要传入Enumeration,而这个只用Vector中有,所以这个多个读取流要加入Vector集合中。注意:它只是对读取流进行合并。

它使用步骤:

1.创建Vector<InputStream>

2.将要合并的InputStream加入Vector

3.通过Vector获取Enumeration

4.创建SequenceInputStream,将Enumeration作为参数传入。

import java.io.*; 
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = newVector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> e = v.elements();

SequenceInputStream sis = new SequenceInputStream(e);
FileOutputStream fos = new FileOutputStream("c:\\4.txt");

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

 

文件的切割和合并

import java.io.*; 
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
//splitFile();
merge();
}
//合并
public static void merge() throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
al.add(new FileInputStream("c:\\2.part"));
al.add(new FileInputStream("c:\\3.part"));
al.add(new FileInputStream("c:\\4.part"));
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = newEnumeration<FileInputStream>()
{
public booleanhasMoreElements()
{
return it.hasNext();
}
public FileInputStreamnextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\0.jpg");
byte[] bys = new byte[1024];
int len = 0;
while ((len=sis.read(bys))!=-1)
{
fos.write(bys,0,len);
}
sis.close();
fos.close();
}
//切割
public static void splitFile() throws IOException
{
FileInputStream fis = new FileInputStream("c:\\1.jpg");
FileOutputStream fos = null;
byte[] bys = new byte[1024*50];
int len = 0;
int count = 2;
while ((len=fis.read(bys))!=-1)
{
fos = newFileOutputStream("c:\\"+(count++)+".part");
fos.write(bys,0,len);
fos.close();
}
fis.close();
}
}

对象序列化:

被序列化的类必须实现Serializable接口,来获得ID.

也可以自己设置ID,例如:static final long serialVersionUID = 42L

static静态成员是不能被序列化的.

transient修饰的成员也是不能被序列化的

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(newFileInputStream("obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj() throws IOException
{
ObjectOutputStream oos =
new ObjectOutputStream(newFileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",97));
oos.close();
}
}
class Person implements Serializable
{
//给类设置ID,
public static final long serialVersionUID = 42L;
String name;
int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String toString()
{
return name+":"+age;
}
}

管道流:

管道流:输入输出可以直接连接,结合线程使用.

    |--管道输入流:PipedInputStream

    |--管道输出流:PipedOutpuStream

import java.io.*; 
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in=in;
}
public void run()
{
try
{
byte[] bys = newbyte[1024];
System.out.println("读取前..没有数据..进入阻塞状态");
int len = in.read(bys);
System.out.println("读取到数据..阻塞状态结束");
String s = newString(bys,0,len);
System.out.println(s);
in.close();
}
catch (IOException e)
{
throw newRuntimeException("管道读取流失败");
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
System.out.println("开始写入数据,等待6秒");
Thread.sleep(6000);
out.write("PipedOutputStream is coming".getBytes());
out.close();
}
catch (Exception e)
{
throw newRuntimeException("管道输出流失败");
}
}
}
class PipedStreamDemo
{
public static void main(String[] args) throws IOException
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
new Thread(new Read(in)).start();
new Thread(new Write(out)).start();
}
}

随机读写RandomAccessFile

该类不算是IO体系中的子类.

而是直接继承自Object.

但是它是IO包的成员,因为它具备读和写功能.

内部封装了一个byte数组,而且通过指针对数组的元素进行操作.

可以通过getFilePointer获取指针位置.

同时可以通过seek改变指针的位置

其实完成读写的原理就是内部封装了字节输入流和输出流.

通过构造函数可以看出,该类只能操作文件.

而且操作的文件还需要指定权限.

如果模式为只读 r,则不会创建文件,回去读取一个已存在的文件,如果该文件不存在,会出现异常

如果模式为 rw,操作的文件不存在,会自动创建,如果存在则不会覆盖

class RandomAccessFileDemo 
{
public static void main(String[] args) throws IOException
{
//writeFile();
//readFile();
writeFile_2();
}

public static void readFile() throws IOException
{
RandomAccessFile raf = newRandomAccessFile("ran.txt","r");
//用seek()方法把指针调到8位置上
//raf.seek(8);

//跳过指定的字节数,skipBytes()只能向前,不能后退
raf.skipBytes(8);

byte[] bys = new byte[4];
raf.read(bys);
String name = new String(bys);

//方法readInt()取一个32位的整数
int age = raf.readInt();

System.out.println("name="+name);
System.out.println("age="+age);
}
public static void writeFile_2()throws IOException
{
RandomAccessFile raf = newRandomAccessFile("ran.txt","rw");
raf.seek(16);//利用seek方法,可以实现指定位置数据的添加和修改
raf.write("周七".getBytes());
raf.writeInt(103);

}
public static void writeFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}
}



----------- android培训java培训、期待与您交流! ------------