黑马程序员——JavaIO流

来源:互联网 发布:知乎英文名 编辑:程序博客网 时间:2024/05/20 19:29

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

一、File类

File是文件和目录(文件夹)路径名的抽象表示形式实现IO的操作,就必须知道硬盘上文件的表现形式。

而Java就提供了一个类File供我们使用。

1:构造方法:

File(String pathname):根据一个路径得到File对象

File(String parent, String child):根据一个目录和一个子文件/目录得到File对象

File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

2:功能

(1)创建功能

public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了

public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了

public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来

(2)删除功能

public boolean delete()

注意事项:

A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。

B:Java中的删除不走回收站。

C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹

(3)重命名功能

public boolean renameTo(File dest)

如果路径名相同,就是改名。

如果路径名不同,就是改名并剪切。

(4)判断功能

public boolean isDirectory():判断是否是目录

public boolean isFile():判断是否是文件

public boolean exists():判断是否存在

public boolean canRead():判断是否可读

public boolean canWrite():判断是否可写

public boolean isHidden():判断是否隐藏

(5)获取功能

public String getAbsolutePath():获取绝对路径

public String getPath():获取相对路径

public String getName():获取名称

public long length():获取长度。字节数

public long lastModified():获取最后一次的修改时间,毫秒值

(6)高级获取功能

public String[] list():获取指定目录下的所有文件或者文件夹的名称数组

public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

(7)过滤器功能

public String[] list(FilenameFilter filter)

public File[] listFiles(FilenameFilter filter)

3:实例

把E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi

改为:E:\评书\三国演义\001_桃园三结义.avi

思路:

A:封装目录

B:获取该目录下所有的文件的File数组

C:遍历该File数组,得到每一个File对象

D:拼接一个新的名称,然后重命名即可。

public static void main(String[] args) {// 封装目录File srcFolder = new File("E:\\评书\\三国演义");// 获取该目录下所有的文件的File数组File[] fileArray = srcFolder.listFiles();// 遍历该File数组,得到每一个File对象for (File file : fileArray) {// E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi// 改后:E:\评书\三国演义\001_桃园三结义.aviString name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.aviint index = name.indexOf("_");String numberString = name.substring(index + 1, index + 4);int endIndex = name.lastIndexOf('_');String nameString = name.substring(endIndex);String newName = numberString.concat(nameString); // 001_桃园三结义.aviFile newFile = new File(srcFolder, newName); // E:\\评书\\三国演义\\001_桃园三结义.avi// 重命名即可file.renameTo(newFile);}}

二、递归

方法定义中调用方法本身的现象。

1:递归注意事项

a: 要有出口,否则就是死递归
b: 次数不能太多,否则就内存溢出
c: 构造方法不能递归使用
d: 方法的嵌套调用,这不是递归。Math.max(Math.max(a,b),c);

2:递归解决问题的思想

a: 找出出口

b: 找到规律

3:案例

需求:递归删除带内容的目录

思路

A:封装目录

B:获取该目录下的所有文件或者文件夹的File数组

C:遍历该File数组,得到每一个File对象

D:判断该File对象是否是文件夹

是:回到B

否:就删除

public static void main(String[] args) {// 封装目录File srcFolder = new File("demo");// 递归实现deleteFolder(srcFolder);}private static void deleteFolder(File srcFolder) {// 获取该目录下的所有文件或者文件夹的File数组File[] fileArray = srcFolder.listFiles();        if (fileArray != null) {// 遍历该File数组,得到每一个File对象for (File file : fileArray) {// 判断该File对象是否是文件夹if (file.isDirectory()) {deleteFolder(file);} else {System.out.println(file.getName() + "---" + file.delete());}}System.out.println(srcFolder.getName() + "---" + srcFolder.delete());}}

三、IO流常用基类

IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。

输入流和输出流相对于内存设备而言的,以程序的角度:

将外设中的数据读取到内存中:输入。

将内存中的数据写入到外设中:输出。

1:IO流的分类

按照数据流向
输入流  读入数据
输出流  写出数据  
按照数据类型
字节流                                      抽象基类 
字节输入流    读取数据    InputStream
字节输出流    写出数据    OutputStream
字符流
字符输入流    读取数据    Reader
字符输出流    写出数据    Writer 

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。

如OutputStream 的子类FileOutputStream

2:字节流

字节流主要是操作byte(字节)的类型数据

(1)FileOutputStream

A: 构造方法

FileOutputStream(File file)
FileOutputStream(String name)

B:字节流写数据的方法

public void write(int b): 写一个字节

public void write(byte[] b): 写一个字节数组

public void write(byte[] b, int off, int len): 写一个字节数组的一部分

\r\n:换行符
追加数据写入:用构造方法带第二个参数是true的情况即可。

FileOutputStream fos = null;//创建对象try {fos = new FileOutputStream("fos.txt");//存储文件fos.write("java".getBytes());//写入数据} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 如果fos不是null,才需要close()if (fos != null) {// 为了保证close()一定会执行,就放到这里了try {fos.close();} catch (IOException e) {e.printStackTrace();}}}

(2)FileInputStream

A: 构造方法

FileInputStream(File file)
FileInputStream(String name)

B: 字节流读取数据的方法

public int read(): 一次读取一个字节
public int read(byte[] b): 一次读取一个字节数组。返回值其实是实际读取的字节个数

public static void main(String[] args) throws IOException {// 创建字节输入流对象FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");// 读取数据// 定义一个字节数组// 数组的长度一般是1024或者1024的整数倍byte[] bys = new byte[1024];int len = 0;while ((len = fis.read(bys)) != -1) {// 如果读取到的实际长度是-1,就说明没有数据了System.out.print(new String(bys, 0, len));}// 释放资源fis.close();}

(3)复制文件

需求:把c盘下的a.txt的内容复制到d盘下的b.txt中

数据源:

c:\\a.txt--读取数据--FileInputStream

目的地:

d:\\b.txt--写出数据--FileOutputStream

public static void main(String[] args) throws IOException {// 封装数据源FileInputStream fis = new FileInputStream("c:\\a.mp4");// 封装目的地FileOutputStream fos = new FileOutputStream("d:\\b.mp4");// 复制数据int by = 0;while ((by = fis.read()) != -1) {fos.write(by);}// 释放资源fos.close();fis.close();}

(4)字节缓冲区

缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率。

字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。

写数据:BufferedOutputStream
读数据:BufferedInputStream

public static void method1(String srcString, String destString)throws IOException {FileInputStream fis = new FileInputStream(srcString);FileOutputStream fos = new FileOutputStream(destString);        byte[] bys = new byte[1024];int len = 0;while ((len = fis.read(bys)) != -1) {fos.write(bys, 0, len);}fos.close();fis.close();}

3:字符转换流

由于字节流操作中文不是特别方便,所以,java就提供了转换流。是字节与字符之间的桥梁。转换流其实是一个字符流
字符流=字节流+编码表。
(1)构造

OutputStreamWriter 字符输出流

public OutputStreamWriter(OutputStream out): 根据默认编码把字节流的数据转换为字符流

public OutputStreamWriter(OutputStream out,String charsetName): 根据指定编码把字节流数据转换为字符流

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"), "UTF-8"); // 指定UTF-8
InputStreamReader 字符输入流

public InputStreamReader(InputStream in): 用默认的编码读取数据

public InputStreamReader(InputStream in,String charsetName): 用指定的编码读取数据

InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "UTF-8");
(2)方法

OutputStreamWriter写数据方法

public void write(int c): 写一个字符

public void write(char[] cbuf): 写一个字符数组

public void write(char[] cbuf,int off,int len): 写一个字符数组的一部分

public void write(String str): 写一个字符串

public void write(String str,int off,int len): 写一个字符串的一部分

flush():刷新缓冲区

close()和flush()的区别?

A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。

B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。

IntputStreamReader读数据方法
public int read(): 一次读取一个字符
public int read(char[] cbuf): 一次读取一个字符数组

(3)子类

OutputStreamWriter = FileOutputStream + 编码表

|—FileWriter = FileOutputStream + 编码表


InputStreamReader = FileInputStream + 编码表

|—FileReader = FileInputStream + 编码表

(4)字符缓冲区

a: 对应类

BufferedWriter: 字符缓冲输出流

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

b: 字符缓冲流的特殊方法

public void newLine(): 根据系统来决定换行符

public String readLine(): 一次读取一行数据。包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

原理:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,将标记前的缓冲数据变成字符串返回。

public static void main(String[] args) throws IOException {// 封装数据源BufferedReader br = new BufferedReader(new FileReader("a.txt"));// 封装目的地BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));// 读写数据String line = null;while ((line = br.readLine()) != null) {bw.write(line);bw.newLine();bw.flush();}// 释放资源bw.close();br.close();}

c: 跟踪行号的缓冲字符输入流

LineNumberReader: 此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。

四、IO包中其他流

1:数据操作流

可以操作基本类型的数据

数据输入流:DataInputStream

DataInputStream(InputStream in)

数据输出流:DataOutputStream

DataOutputStream(OutputStream out) 

private static void read() throws IOException {// DataInputStream(InputStream in)// 创建数据输入流对象DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));// 读数据byte b = dis.readByte();short s = dis.readShort();int i = dis.readInt();long l = dis.readLong();float f = dis.readFloat();double d = dis.readDouble();char c = dis.readChar();boolean bb = dis.readBoolean();// 释放资源dis.close();System.out.println(b);System.out.println(s);System.out.println(i);System.out.println(l);System.out.println(f);System.out.println(d);System.out.println(c);System.out.println(bb);}private static void write() throws IOException {// DataOutputStream(OutputStream out)// 创建数据输出流对象DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));// 写数据了dos.writeByte(10);dos.writeShort(100);dos.writeInt(1000);dos.writeLong(10000L);dos.writeFloat(12.34F);dos.writeDouble(12.56);dos.writeChar('a');dos.writeBoolean(true);// 释放资源dos.close();}
2:内存操作流

之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内存操作流。

用于处理临时存储信息的,程序结束,数据就从内存中消失。

操作字节数组

ByteArrayInputStream将内容写到内存中

ByteArrayOutputStream   将内存中的数据写出

操作字符数组

CharArrayReader

CharArrayWrite

操作字符串

StringReader

StringWriter

public static void main(String[] args) throws IOException {// 写数据ByteArrayOutputStream baos = new ByteArrayOutputStream();// 写数据for (int x = 0; x < 10; x++) {baos.write(("hello" + x).getBytes());}// 释放资源// 通过查看源码知道这里什么都没做,所以根本需要close()// baos.close();byte[] bys = baos.toByteArray();//得到真正的数据// 读数据// ByteArrayInputStream(byte[] buf)ByteArrayInputStream bais = new ByteArrayInputStream(bys);int by = 0;while ((by = bais.read()) != -1) {System.out.print((char) by);}}

3:打印流

字节流打印流      PrintStream

字符打印流          PrintWriter

特点:

A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
B:可以操作任意类型的数据。
C:如果启动了自动刷新,能够自动刷新。
D:该流是可以直接操作文本文件的。

构造:

public PrintStream(File file) throws FileNotFoundException

public PrintStream(OutputStream out)

PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

还是应该调用println()的方法才可以

这个时候不仅仅自动刷新了,还实现了数据的换行。

4:标准输入输出流

System类中的两个成员变量:

public static final InputStream in “标准”输入流。

public static final PrintStream out “标准”输出流。

InputStream is = System.in;

PrintStream ps = System.out;

(1)键盘录入数据

A:main方法的args接收参数。

java HelloWorld 

B:Scanner(JDK5以后的)

Scanner sc = new Scanner(System.in);

String s = sc.nextLine();

int x = sc.nextInt()

C:通过字符缓冲流包装标准输入流实现

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

(2)获取标准输入流

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));bw.write("hello");bw.write("world");bw.write("java");bw.newLine();bw.flush();bw.close();

5:随机访问流

RandomAccessFile类不属于流,是Object类的子类。

但它融合了InputStream和OutputStream的功能。

支持对随机访问文件的读取和写入。

方法:

public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。

模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据 

6:合并流

SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

构造方法

SequenceInputStream(InputStream s1, InputStream s2)  

SequenceInputStream(Enumeration<? extends InputStream> e)

把多个文件的内容写入到一个文本文件

需求:把a.txt, b.txt, c.txt复制到d.txt

public static void main(String[] args) throws IOException {// SequenceInputStream(Enumeration e)// Enumeration是Vector中的一个方法的返回值类型。// Enumeration<E> elements()Vector<InputStream> v = new Vector<InputStream>();InputStream s1 = new FileInputStream("a.txt");InputStream s2 = new FileInputStream("b.txt");InputStream s3 = new FileInputStream("c.txt");v.add(s1);v.add(s2);v.add(s3);Enumeration<InputStream> en = v.elements();SequenceInputStream sis = new SequenceInputStream(en);BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d.txt"));// 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写byte[] bys = new byte[1024];int len = 0;while ((len = sis.read(bys)) != -1) {bos.write(bys, 0, len);}bos.close();sis.close();}

7:序列化流

序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。

对象 -- 流数据(ObjectOutputStream)

反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。

流数据 -- 对象(ObjectInputStream)

被操作的对象需要实现Serializable。
类通过实现java.io.Serializable接口以启用序列化功能,Serializable只是一个标记接口。

用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本。

private static void read() throws IOException, ClassNotFoundException {// 创建反序列化对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));// 还原对象Object obj = ois.readObject();// 释放资源ois.close();// 输出对象System.out.println(obj);}private static void write() throws IOException {// 创建序列化流对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));// 创建对象Person p = new Person("Donald", 27);// public final void writeObject(Object obj)oos.writeObject(p);// 释放资源oos.close();}public class Person implements Serializable {private static final long serialVersionUID = -2071565876962058344L;//加入IDprivate String name;private transient int age;//使用transient关键字声明不需要序列化的成员变量public Person() {super();}public Person(String name, int age) {super();this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";}}

8:Properties集合

Properties:属性集合类。是一个可以和IO流相结合使用的集合类。

Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 
是Hashtable的子类,说明是一个Map集合。

(1)特殊功能:

public Object setProperty(String key,String value):添加元素

public String getProperty(String key):获取元素

public Set<String> stringPropertyNames():获取所有的键的集合

(2)Properties和IO流的结合使用,这里的集合必须是Properties集合

public void load(Reader reader):把文件中的数据读取到集合中

public void store(Writer writer,String comments):把集合中的数据存储到文件

private static void myStore() throws IOException {// 创建集合对象Properties prop = new Properties();prop.setProperty("Jesus", "27");prop.setProperty("Donald", "30");prop.setProperty("Lucy", "18");//public void store(Writer writer,String comments):把集合中的数据存储到文件Writer w = new FileWriter("name.txt");prop.store(w, "helloworld");w.close();}private static void myLoad() throws IOException {Properties prop = new Properties();// public void load(Reader reader):把文件中的数据读取到集合中// 注意:这个文件的数据必须是键值对形式Reader r = new FileReader("prop.txt");prop.load(r);r.close();System.out.println("prop:" + prop);}
10:NIO

 NIO其实就是新IO的意识。NIO包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。

JDK7的之后的NIO:

JDK7的之后的nio:

Path:路径

Paths:有一个静态方法返回一个路径

public static Path get(URI uri)

Files:提供了静态方法供我们使用

public static long copy(Path source,OutputStream out):复制文件

public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption...options)

五、流的操作规律

之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道对象的开发时用到哪些对象,只要通过四个明确即可。

1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer

2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream 
到这里,就可以明确需求中具体要使用哪个体系。

3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流

4、是否需要其他额外功能
是否需要高效(缓冲区):
是,就加上buffer


0 0