黑马程序员————IO流(2)

来源:互联网 发布:sqoop导入数据到mysql 编辑:程序博客网 时间:2024/06/05 13:56

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-------


一、File类

 

用来将文件和文件夹封装成对象

方便对文件和文件夹的属性进行操作

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

 

流对象:

FileReader

FileWriter

FileOutputStre

FileInputStream

 

常用的方法:

1.构造方法和字段

//1.可以将一个已存在或者不存在的文件或者目录封装成对象

File f1 = new File("f:\\a.txt");


//2.这个和1比较可以改变目录和目录下的其他文件,不局限于f盘和f盘下的a.txt

File f2 = new File("f:\\","a.txt");


//3.和2比较可以对f进行file对象操作,原来只能按照字符串进行操作

File f = new File("f:\\");

File f3 = new File(f,"a.txt");


//4.字段摘要

/*File f4 = new File("f:\\abc\\a.txt");在UNIX下不可以,

UNIX只认同“/”所以可以用file.separator*/

File f4 = new File("f:"+File.separator+"abc"+File.separator+"a.txt");

 

2.常用的方法

(1)获取

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

//获取名称

String name = file.getName();


//获取文件的路径

String path = file.getAbsolutePath();//绝对路径

String path1 = file.getPath();//相对路径


//文件大小

long len = file.length();


//获取文件的修改时间

long time = file.lastModified();

 

补充:获取有效的时间(*)

long time = file.lastModified();

Date date = new Date(time);

DateFormat dateFormat =  DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);

String str_time = dateFormat.format(date);

 

(2)创建和删除

 

文件的创建和删除

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

// 1.文件的创建,和输出流不一样,如果文件存在则不创建,反之则创建

file.createNewFile();


//2.文件的删除

file.delete();

 

文件夹的创建和删除

//1.单目录文件夹

File dir1 = new File("nba");

dir1.mkdir();//创建

dir1.delete();//删除

 

//2.多级目录文件夹

File dir = new File("abc\\v\\c\\d\\v\\h\\j\\k\\l");//将“l”封装成了对象

dir.mkdirs();

dir.delete();//删除的是“l”文件夹

 

注意:windows删除是从内往外删除,如果目录中有内容目录则不会被删除

 

(3)判断

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

//判断文件是否存在

file.exists();


//判断是否是文件

file.isFile();


//判断是否是目录

file.isDirectory();

 

注意:最好先判断文件是否存在,如果文件不存在,判断的结果都是false 

 

(4)重命名

File file = new File("f:\\0.jpg");

File file2 = new File("f:\\3.jpg");

File file3 = new File("d:\\aa.jpg");


//重命名

file.renameTo(file2);


//剪切

file.renameTo(file3);

 

(5)获取系统的根目录及容量的获取

File file = new File("d:\\");

//可用空间,迅雷看看下载就选择最大空闲的盘符

System.out.println(file.getFreeSpace());


//总容量

System.out.println(file.getTotalSpace());


//虚拟机可用空间(不常用)

System.out.println(file.getUsableSpace());

 

(6)获取目录内容

/*

 * 获取当前目录下文件以及文件夹名称,包含隐藏的文件,调用list方法

 * 的file对象中封装的必须是目录,否则会发生空指针异常,如果访问的

 * 系统级目录也会发生空指针异常,如果目录存在但是没有内容,会返回

 * 一个数组,但是长度为0。

*/

File file = new File("f:\\");

String[] names = file.list();

for(String name:names){

System.out.println(name);

}

 

(7)过滤器


过滤器1的定义:

public class FileByJava implements FilenameFilter {@Overridepublic boolean accept(File dir, String name) {//遍历数组,进行运算,只要返回的是true,就存储文件return name.endsWith(".java");}}过滤f盘下的".java"文件:File file = new File("f:\\");String[] names = file.list(new FileByJava());for(String name:names){System.out.println(name);}

过滤器2的定义:(过滤隐藏文件)

public class FilterByHidden implements FileFilter {@Overridepublic boolean accept(File pathname) {return !pathname.isHidden();}}

过滤器3的定义:(根据后缀名过滤)

public class SuffixFilter implements FilenameFilter {private String suffix;private SuffixFilter(String suffix) {super();this.suffix = suffix;}@Overridepublic boolean accept(File dir, String name) {return name.endsWith(suffix);}}

例子:

1.深度遍历文件夹 ,并且有层级显示

import java.io.File;public class TestDemo6 {/** * @param args */public static void main(String[] args) {File dir = new File("f:\\demodir");listAll(dir,0);}private static void listAll(File dir,int level) {System.out.println(getSpace(level)+dir.getName());level++;//获取指定目录下的当前的所有文件夹或者文件对象File[] files = dir.listFiles();for(int x = 0; x<files.length; x++){if(files[x].isDirectory())listAll(files[x],level);else System.out.println(getSpace(level)+files[x].getAbsolutePath());}}private static String getSpace(int level) {StringBuilder sb = new StringBuilder();for(int x=0; x<level; x++){sb.append("    ");}return sb.toString();}}

2.递归

定义:函数自身或者间接的调用了自身

注意:(1)递归一定要明确条件,否则容易栈溢出,(2)注意递归的次数,防止栈溢出

 

求二进制

private static void toBin(int num) {if(num>0)toBin(num/2);System.out.print(num%2);}

求和

private static int getSum(int num) {if(num==1)return 1;return num+getSum(num-1);}

3.删除目录

 

需要深度遍历目录,必须从里面往外删除

import java.io.File;public class TestDemo8 {/** * @param args */public static void main(String[] args) {File dir = new File("f:\\demodir");removeDir(dir);}private static void removeDir(File dir) {File[] files = dir.listFiles();for(File file : files){if(file.isDirectory())removeDir(file);elseSystem.out.println(file+" "+file.delete());}System.out.println(dir+" "+dir.delete());}}

二、Properties

 

特点:

1.该集合中的键和值嗾使字符串类型

2.该集合中的数据可以保存到流中,或者从流中获取

 

通常该集合用于操作以键值对形式存在的配置文件

 

1.Properties集合的存和取

Properties prop = new Properties();//存储元素,用到setProperty方法prop.setProperty("zhangsan", "31");prop.setProperty("lisi", "28");prop.setProperty("xiaoqiang", "15");//修改元素,键不变值改变prop.setProperty("zhangsan", "39");//取元素,用到setProperty方法Set<String> names = prop.stringPropertyNames();for(String name : names){String value = prop.getProperty(name);System.out.println(name+":"+value);}

2.list方法

Properties prop = new Properties();prop.setProperty("zhangsan", "31");prop.list(System.out);

3.store方法

Properties prop = new Properties();prop.setProperty("zhangsan", "31");prop.setProperty("lisi", "28");prop.setProperty("xiaoqiang", "15");//想要持久化存储信息需要关联流FileOutputStream fos = new FileOutputStream("info.txt");prop.store(fos, "info");fos.close();

4.修改配置信息

 

load方法:

//集合中的数据来源于一个文件,注意必须要保证该文件中的数据时键值对,需要用到读取流Properties prop = new Properties();FileInputStream fis = new FileInputStream("info.txt");//使用load方法prop.load(fis);prop.list(System.out);fis.close();

修改配置文件

/* * 1.读取这个文件,并将这个文件中的键值数据存储到集合中 * 2.在通过集合对数据进行修改 * 3.在通过流将修改后的数据存储到文件中 *///读取文件File file = new File("info.txt");if(!file.exists())file.createNewFile();FileReader fr = new FileReader("info.txt");//创建集合存储数据Properties prop = new Properties();//将流中的数据存储到集合中prop.load(fr);//修改信息prop.setProperty("zhangsan", "100");//将修该后的数据存储FileWriter fw = new FileWriter(file);prop.store(fw, "info1");fr.close();fw.close();


注意:

不要紧跟着输入流创建后创建输出流,将输出流在修改配置文件后再创建,因为原来的数据会被覆盖。 

 

练习1:获取一个应用程序运行次数,如果超过5次,给出使用次数已到请注册的提示,并不要运行程序

 

思路:

1.应该有计数器

 

每次程序的启动都需要计数一次,并且是在原有的次数上进行计数

 

2.计数器是一个变量

 

程序启动时进行计数,计数器必须存在于内存并进行运算,而我们需要多次启动同一个应用程序,使用同一个计数器。而这就需要计数器的生命周期变长,从内存存储到硬盘文件中。

 

3.如何使用这个计数器呢?

 

首先,程序启动时,应该先读取这个用于记录计数器信息的配置文件,获取上一次计数器次数,并进行使用次数的判断。其次,对该次数进行自增,并自增后的次数重新存储到配置文件中。

 

4.文件中的信息该如何存储并体现呢?

 

直接存储数值可以,但不明确该数据的含义,所以起名字就显得比较重要。这就有了名字和值得对应,所以可以使用键值对,可用映射关系map集合搞定,又需要读取硬盘上的数据,所以map+io=properties

//将配置文件封装成file对象File confile = new File("count.properties");if(!confile.exists())confile.createNewFile();FileInputStream fis = new FileInputStream(confile);Properties prop = new Properties();prop.load(fis);//从集合中通过键获取次数String value = prop.getProperty("time");int count = 0;if(value!=null){count=Integer.parseInt(value);if(count>=5)throw new RuntimeException("使用次数已到,请注册,购买正版!!");}count++;//将改变后的次数重新存储到集合中prop.setProperty("time", count+"");FileOutputStream fos = new FileOutputStream(confile);prop.store(fos, "");fos.close();fis.close();}

练习2:建立指定扩展名的文件清单列表


思路:

1.必须进行深度遍历

2.要在遍历的过程中进行过滤,将符合条件的内容都存储到容器中

3.对容器中的这些内容进行遍历,并将绝对路径写入到文件中

import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.FilenameFilter;import java.io.IOException;import java.util.ArrayList;import java.util.List;public class TestDemo9 {/** * @param args */public static void main(String[] args) {File dir = new File("F:\\Workspaces\\MyEclipse 10\\Review\\src");FilenameFilter filter = new FilenameFilter() {@Overridepublic boolean accept(File dir, String name) {return name.endsWith(".java");}};List<File> list = new ArrayList<File>();getFile(dir, filter, list);File destFile = new File(dir,"test.txt");write2File(list, destFile);}public static void getFile(File dir ,FilenameFilter filter,List<File> list){File[] files = dir.listFiles();for(File file : files){if(file.isDirectory()){getFile(file, filter, list);}else{if(filter.accept(dir, file.getName())){list.add(file);}}}}public static void write2File(List<File> list,File destFile){BufferedWriter bufw = null;try {bufw = new BufferedWriter(new FileWriter(destFile));for(File file :list){bufw.write(file.getAbsolutePath());bufw.newLine();bufw.flush();}} catch (IOException e) {throw new RuntimeException("写入失败");}finally{if(bufw!=null)try {bufw.close();} catch (IOException e) {throw new RuntimeException("关闭失败");}}}}

三、IO包中的其他类

 

1.打印流

 

PrintStream


(1)提供了打印的方法可以对多种数据类型值进行打印,并保持数据的表示形式

(2)它不抛IoException


构造函数,接受三种不同的类型的值

(1)字符串路径

(2)File对象

(3)字节输出流

PrintStream out = new PrintStream("print.txt");//out.write(97);结果是a,只写最低八位out.print(97);//将97先变成字符,保持原样的数据打印到目的地out.close();

PrintWriter


构造函数参数:

(1)字符串路径 

(2)File对象

(3)字节输出流

(4)字符输出流

 

例1

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));PrintWriter out = new PrintWriter(System.out);String line = null;while((line=bufr.readLine())!=null){if("over".equals(line))break;out.println(line.toUpperCase());out.flush();}out.close();bufr.close();

例2

PrintWriter out = new PrintWriter(System.out,true);替换上面的PrintWriter out = new PrintWriter(System.out);//可以不用刷新,即可以不用写out.flush();

例3

PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);替换上面的PrintWriter out = new PrintWriter(System.out,true);//可以实现自动刷新

2.序列流-SequenceInputstream

 

对多个流进行合并

 

例子1:将1.txt,2.txt,3.txt文件中的数据合并成一个文件中

ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();for(int x=1; x<=3; x++){al.add(new FileInputStream(x+".txt"));}Enumeration<FileInputStream> en = Collections.enumeration(al);SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream("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();}

例子2:文件的切割

import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class TestDemo10 {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {File file = new File("f:\\1.mp3");spiltFile(file);}private static void spiltFile(File file) throws IOException {FileInputStream fis = new FileInputStream(file);byte[] buf = new byte[1024*1024];FileOutputStream fos = null;int len = 0;int count = 1;File dir = new File("f:\\properties");if(!dir.exists())dir.mkdir();while((len=fis.read(buf))!=-1){fos=new FileOutputStream(new File(dir,(count++)+".part"));fos.write(buf,0,len);}fis.close();fos.close();}}

例子3文件的切割加配置文件

 

切割文件是,必须记录住被切割文件的名称,以及切割出来的碎片文件的个数,以便于合并。这个信息为了描述,使用键值对的方式,用到了properties对象

package io;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.util.Properties;public class TestDemo10 {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {File file = new File("f:\\1.flv");spiltFile(file);}private static void spiltFile(File file) throws IOException {FileInputStream fis = new FileInputStream(file);byte[] buf = new byte[1024*1024];FileOutputStream fos = null;int len = 0;int count = 1;Properties prop = new Properties();File dir = new File("f:\\properties");if(!dir.exists())dir.mkdir();while((len=fis.read(buf))!=-1){fos=new FileOutputStream(new File(dir,(count++)+".part"));fos.write(buf,0,len);fos.close();}prop.setProperty("partCount", count+"");prop.setProperty("fileName", file.getName());fos=new FileOutputStream(new File(dir, (count)+".properties"));prop.store(fos, "info");fis.close();fos.close();}} 

例子4 文件的合并加配置文件

package io;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.SequenceInputStream;import java.util.ArrayList;import java.util.Collections;import java.util.Enumeration;import java.util.Properties;import filter.SuffixFilter;public class TestDemo11 {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {File dir = new File("f:\\properties");//因为该目录不知道有“x.properties”x是多少,但是只有一个扩展名为properties文件所以用到过滤器File[] files = dir.listFiles(new SuffixFilter(".properties"));if(files.length!=1){throw new RuntimeException(dir+",该目录下没有properties文件或者不唯一");}//记录配置文件对象File confile = files[0];//获取该文件中的信息Properties prop = new Properties();FileInputStream fis = new FileInputStream(confile);prop.load(fis);String fileName = prop.getProperty("fileName");int count = Integer.parseInt(prop.getProperty("partCount"));//获取该目录下的所有碎片文件File[] partFiles = dir.listFiles(new SuffixFilter(".part"));if(partFiles.length!=(count-1)){throw new RuntimeException("碎片文件不符文要求,个数不对,应该为"+count+"个");}ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();for(int x=1; x<partFiles.length; x++){al.add(new FileInputStream(partFiles[x]));}Enumeration<FileInputStream> en = Collections.enumeration(al);SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream(fileName);byte[] buf = new byte[1024];int len = 0;while((len=sis.read(buf))!=-1){fos.write(buf,0,len);}fos.close();sis.close();}}


 

3.对象的序列化-ObjectInputStrea和ObjectOutputStream

 

对象的序列化:将数据作为对象放入硬盘进行持久化存储

//一般存储对象的文件的后缀名用objectObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));//对象的序列化,被序列化的对象必须实现Serializable接口oos.writeObject(new Person("小强",25));oos.close();

对象的反序列化:对象被序列化存储后,读取序列化的对象


ObjectInputStream对以前ObjectOutputStream写入的基本数据和对象进行反序列化

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));//因为知道文件对象是Person、,所以可以强转Person p = (Person) ois.readObject();System.out.println(p.getName()+":"+p.getAge());

Serializable接口

 

如果读取序列化对象文件,而反序列化过程中对象变了,则会放生异常。

 

解释:例如Person实现了Serializable接口,此时该Person具备了ID号,而序列化过程,序列化和这个来相关联,而反序列化过程中Person类改变了,所以ID号变了,因此放生了异常。

 

总的来说:Serializable就是给序列化的类加上一个ID号,用于判断类和对象是否是同一个版本

 

怎么给可序列化类声明一个ID号呢?

 

public class Person implements Serializable{

private static final long serialVersionUID =125845641651L;

后面代码略

 

序列化这个知识点在以后的web开发中会用到。

 

transient关键字


比如:有些数据,不是公共数据,对象特有的,不能静态

 

例如:不想将name这个非静态的数据序列化。

private transient String name;

private static int age;


结果反序列化的结果是:

null:0

 

4.RandomAccessFile-随机访问文件


不是IO体系的子类


特点:

1.该对象既能读又能写

2.该对象内部维护了一个byte数据,并通过指针操作数组中的元素

3.可以通过getFilePointer方法获取指针的位置,和通过get方法设置指针的位置

4.其实该对象就是讲字节输入流和输出进行了封装

5.该对象的源和吗目的只能是文件

 

1.写数据 

//如果文件不存在,则创建;如果存在则不会创建RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "rw");raf.write("张三".getBytes());//raf.write(97);只写最低8位raf.writeInt(97);//按4个字节写,先写高位raf.write("小王".getBytes());raf.writeInt(25);raf.close();

2.读取或随机读取

ranacc.txt文件内容

读取:

RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r");byte[] buf = new byte[4];raf.read(buf);String name = new String(buf);//因为年龄是整数,用readInt更方便int age = raf.readInt();System.out.println(name);System.out.println(age);raf.close();

随机读取:

RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r");//通过seek来设置指针的位置raf.seek(1*8);//随机的读取,只要指定指针的位置即可byte[] buf = new byte[4];raf.read(buf);String name = new String(buf);int age = raf.readInt();System.out.println("name="+name);System.out.println("age="+age);//指针的位置System.out.println("pos:"+raf.getFilePointer());raf.close();

3.随机写

紧接着rannac.txt后面写入

RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "rw");raf.seek(raf.length());raf.write("哈哈".getBytes());raf.close();

用处:多线程写入用到RandomAccessFile。

 

 

5.管道流-PipedInputStream和PipedOutputStream

 

不能单线程使用,不然会死锁

 

例子:

package io;import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;public class PipedDemo {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {PipedInputStream input = new PipedInputStream();PipedOutputStream output = new PipedOutputStream();input.connect(output);new Thread(new Input(input)).start();new Thread(new Output(output)).start();}}class Input implements Runnable{private PipedInputStream in;Input(PipedInputStream in) {super();this.in = in;}@Overridepublic void run() {try {byte[] buf = new byte[1024];int len = in.read(buf);String s = new String(buf,0,len);System.out.println(s);in.close();} catch (IOException e) {e.printStackTrace();};}}class Output implements Runnable{private PipedOutputStream out; Output(PipedOutputStream out) {super();this.out = out;}@Overridepublic void run() {try {Thread.sleep(5000);out.write("s=hi,管道来了".getBytes());} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}

6.操作基本数据类型:DataOutputStream 和DataInputStream 

 

写数据

DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));dos.writeUTF("你好");dos.close();

读数据

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));String str = dis.readUTF();System.out.println(str);dis.close();

7.操作字节数组

 

不需要关闭流,此类中的close方法在关闭此流后仍可被调用。该对象一创建必须要有源,源是字节数组。

ByteArrayInputStream bis = new ByteArrayInputStream("abcd".getBytes());ByteArrayOutputStream bos = new ByteArrayOutputStream();int ch=0;while((ch=bis.read())!=-1){bos.write(ch);}System.out.println(bos.toString());

8.操作字符数组


CharArrayReader;

CharArrayWriter

类似上,源是字符数组。


9.操作字符串


StringReader;

StringWriter

类似上,源是字符串。


------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-------


 

0 0
原创粉丝点击