file类
-
boolean createNewFile():创建当前File对象所描述的路径的文件
-
boolean mkdirs():创建当前File对象所描述的路径的文件夹(如果父级路径不存在,那么自动创建父级路径)
-
delete在删除文件夹的时候,只能删除空文件夹
-
renameTo(File dest)重命名
如果在同一个文件夹下,修改路径,就是重命名
如果在不同文件夹下,修改路径,就是剪切 -
exists():判断当前调用者File对象,是否存在
isFile():判断当前调用者File对象,是否是文件
isDirectory():判断当前调用者File对象,是否是文件夹 -
getAbsolutePath():获取当前File对象的绝对路径
getPath():获取的就是在构造方法中封装的路径
getName():获取最底层的简单的文件或者文件夹名称(不包含所造目录的路径)
length():获取文件的字节个数 -
String[] list():获取当前文件夹下的所有文件和文件夹的名称,到一个字符串数组中
File[] listFiles():获取当前文件夹下的所有文件和文件夹的File对象,到一个File对象数组中
* 案例
递归方式列出某个目录下的所有文件夹名和文件名?
public void print(File f){
File[] files = f.listFiles();
for (File ff:files){
if(ff.isDirectory()){
System.out.println("当前目录:"+ff.getName());
print(ff);
}else{
System.out.println("当前文件:"+ff.getName());
}
}
}
* 文件过滤
FilenameFilter过滤器中的accept方法接收两个参数,一个当前文件或文件夹所在的路径,一个是当前文件或文件夹对象的名称。
FileFilter 过滤器中的accept方法接受一个参数,这个参数就当前文件或文件夹对象
当我们需要过滤文件名称时就可以使用FilenameFilter这个过滤器,当我们想对当前文件和文件夹进行过滤,就可以使用FileFilter
获得F:/test目录下所有以a开头的文件
public void filterFile(File file){
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.startsWith("a")) {
return true;
}
return false;
}
});
for (File f:files){
System.out.println(f.getName());
}
}
获得F:/test目录下所有以b开头的文件夹
public void filterDir(File file){
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()){
if (pathname.getName().startsWith("b")) {
return true;
}
}
return false;
}
});
for (File f:files){
System.out.println(f.getName());
}
}
io流
* io缓冲流高效原因及读写原理
* 字符流
@Test
public void test4(){
BufferedReader reader=null;
BufferedWriter writer=null;
try {
reader = new BufferedReader(new FileReader("E:/java/m.txt"));
writer = new BufferedWriter(new FileWriter("E:/java/rr.txt"));
String data;
while ((data=reader.readLine())!=null){
writer.write(data);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
* 字节流
@Test
public void test5(){
BufferedInputStream is=null;
BufferedOutputStream os=null;
try {
is = new BufferedInputStream(new FileInputStream("E:/java/b.txt"));
os = new BufferedOutputStream(new FileOutputStream("E:/java/bb.txt"));
byte[] bytes = new byte[1024];
int len;
while ((len=is.read(bytes))!=-1){
os.write(bytes,0,len);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(os!=null){
try {
os.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (is!=null){
try {
is.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
* 转换流
字节流转换为字符流。
有时,我们需要将字节流转换为字符流,使用InputStreamReader和OutputStreamWriter。
io流中拷贝uft-8格式文件举例
PrintStream(字节打印流)
输出
注意事项:
1、如果直接使用System.out的方式来获取PrintStream的对象,这个对象默认关联的输出目的地就是控制台;如果手动创建PrintStream的对象,那么关联的就是指定的设备。
2、PrintStream中重载了很多print和println的方法,有两个比较特殊,print(char[] arr)、print(Object obj)。一般的数组使用print方法,会直接打印数组的地址,唯独字符数组打印之后出现的是数组的内容。普通的数组走的都是println(Object obj)方法,先获取了数组的toString的内容,也就是数组的地址,而字符数组走的是println(char[] arr)方法,直接调用了write方法用于输出字符内容
PrintWriter(字符打印流)
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new FileReader("c:/bbb.txt"));
PrintWriter pw = new PrintWriter("D:/bbb.txt");
String str = "";
while((str =br.readLine())!=null){
pw.println(str);
}
pw.close();
br.close();
}
Properties
(1)概述
Properties对象表示一个持久的属性集
属性集:属性名称和属性值的对应关系,其实还是一个双列集合
持久的:可以保存到流中,也可以从流中读取。可以很方便和文件进行交互
Properties没有泛型,因为表示一个配置文件中的信息,而配置文件中都是字符串,所以Properties类型不需要使用广泛的类型,存储的键和值都是字符串类型
Properties是Hashtable的子类,所以可以当做普通的Map来使用
(2)Properties中的特有方法
1、getProperty(String propertyName):根据一个字符串类型的属性名称,获取一个对应的属性值
2、setProperties(String propertyName, String propertyValue):将一个属性名和对应的属性值添加到当前对象中
3、stringPropertyNames():获取当前属性集对象中的所有属性名称的Set集合
示例代码
public class Demo08_Properties类 {
public static void main(String[] args) {
Properties p = new Properties();
p.setProperty("id","111"); // 和Map的put类似
p.setProperty("name", "zhangsan");
p.setProperty("address","beijing");
System.out.println(p.getProperty("id")); //和Map的get类似
System.out.println(p.getProperty("name"));
System.out.println(p.getProperty("address"));
Set<String> set = p.stringPropertyNames(); //和Map中的keySet()类似
for(String name:set){
System.out.println(name);
}
}
}
(3)Properties和配置文件交互的方式
load(InputStream is)
从流is中,加载配置文件的信息,到内存的Properties对象中,形成双列集合
load(Reader r)
从流r中,加载配置文件的信息,到内存的Properties对象中,形成双列集合
说明:无论是is和r,关联的都是对应的配置文件
store(OutputStream os)
将内存中的Properties对象中键值对信息,写出到流os中
store(Writer w)
将内存中的Properties对象中键值对信息,写出到流w中
说明:无论是os还是w,关联的都是对应的配置文件
注意事项
1、使用prop修改了属性值之后,文件中的属性值不会发生变化,因为prop只修改了内存中的对象数据,没有同步到文件中。必须调用store方法之后,才能将变化同步到文件。
2、调用store方法时,一般需要指定更新属性的原因,即第二个参数comments,如果没有注释,可以传入null;如果有注释,必须是纯英文注释。
示例代码
public class Demo09_Properties操作properties文件 {
public static void main(String[] args) {
Properties p = new Properties();
InputStream is;
try {
is = new FileInputStream("test.properties");
p.load(is); // 加载properties文件
/* String id = p.getProperty("user.id"); //读取文件内容
String name = p.getProperty("user.name");
String address = p.getProperty("address");
System.out.println(id);
System.out.println(name);
System.out.println(address);
*/
p.setProperty("user.name","李四"); // 向文件中设置值
p.setProperty("address","shanghai");
p.setProperty("user.age","22");
// 以上代码只是把值设置到了内存中的p对象中,还没有向文件中写
OutputStream os = new FileOutputStream("test.properties");
p.store(os, "zhushishuomingneirong");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、对象序列化(对象流)
当创建对象时,程序运行时它就会存在,但是程序停止时,对象也就消失了.
但是如果希望对象在程序不运行的情况下仍能保存其信息,将会非常有用,对象将被重建并且拥有与程序上次运行时拥有的信息相同。可以使用对象的序列化。
对象的序列化: 将内存中的对象直接写入到文件设备中或在网络上传输。
对象的反序列化: 将文件设备中持久化的数据转换为内存对象。
基本的序列化由两个方法产生:一个方法用于序列化对象并将它们写入一个流,另一个方法用于读取流并反序列化对象。
(1)ObjectOutputStream
构造方法:ObjectOutputStream(OutputStream os):将一个普通的字节输出流包装成对象输出流
最常用方法:writeObject(Object obj):这个过程叫做序列化
(2)ObjectInputStream
readObject() 这个过程叫做反序列化
注意事项
1、连续序列化对象
当连续两次序列化同一对象引用时,并不会有两个对象被序列化。即使当第一次序列化完成后,修改了对象的值,再次进行序列化,被序列化对象的值也不会发生变化。
第2次和第1次写的是同一个对象,第2次序列化时并不会有两个对象被序列化。第2次只是输出一个序列号编号
版本号问题
修改了本地的User代码,新的类型和文件中对象的类型已经不一致,所以两个版本冲突了,标志就是两个版本的序列化版本id不同。
解决:不要使用自动生成的序列化版本ID,手动给定一个序列化版本ID,将来这个类型是否发生了版本变化,主要取决于程序员是否手动修改了这个类型的版本ID,如果修改了,那么文件中的对象类型和本地类型就不兼容,如果没有修改这个版本ID,那么无论怎样修改了类型内容,都可以做到文件对象类型和本地类型兼容。
案例
class User implements Serializable{
private static final long serialVersionUID = 1L;
// 手动设置序列化版本——解决版本冲突问题
private int id;
private String name;
private int age;
private String address;
public User() {
super();
}
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public User(int id, String name, int age, String address) {
super();
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objs.txt"));
Student stu = new Student(1,"zhangsan",20);
oos.writeObject(stu);
stu.setName("李四");
oos.writeObject(stu); // 和第1次写的是同一个对象,第2次序列化时并不会有两个对象被序列化。第2次只是输出一个序列号编号
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objs.txt"));
Student stu1 = (Student)ois.readObject();
System.out.println(stu1);
Student stu2 = (Student)ois.readObject();
System.out.println(stu2);
Student stu3 = (Student)ois.readObject();
System.out.println(stu3); // 只存了两次,第3次读取时报错
ois.close();