第十六节、轻松学Java_输入输出流

流的概念与文件类

在 Java 语言中,将与不同输入输出设备之间的数据传输抽象为流,程序允许通过流的方式与输入输出设备进行数据传输。

文件类即File类,通过查找相关的API手册即可获得相关的类、方法以及属性的使用,这是十分关键的一环,以后很多不知名的类,我们只需要大概有个印象就行,到时候通过实际使用过程中查找相对应的手册即可,当然熟悉相关类的基本方法的使用也是十分关键的。

文件类的常用方法

package com.test;

import java.util.Scanner;
import java.io.File;
import java.io.IOException;
public class Test 
{
	public static void main(String[] args)
	{
		Scanner scanner=new Scanner(System.in);
		System.out.println("请输入文件名,例如:d:\\1.png");
		String s=scanner.nextLine();
		//这里只是创建了一个指定路径与文件名的文件对象,并不是真实创建了一个文件,暂且称为映射文件。
		File file=new File(s);
		
		System.out.println("文件名:"+file.getName());
		System.out.println("文件大小为:"+file.length()+"字节");
		System.out.println("文件所在路径为:"+file.getAbsolutePath());
		
		if (file.isHidden())
		{
			System.out.println("该文件是一个隐藏文件");
		}
		else
		{
			System.out.println("该文件不是一个隐藏文件");
		}
		//如果文件不存在(真实文件),就创建真实文件
		if (!file.exists())
		{
			System.out.println("该文件不存在");
			try
			{
				//这里才是创建了真实文件
				file.createNewFile();
				System.out.println("新文件创建成功");
			}
			catch(IOException e){}
		}
	}
}

输出:
请输入文件名,例如:d:\1.png
d:\hello.txt
文件名:hello.txt
文件大小为:0字节
文件所在路径为:d:\hello.txt
该文件不是一个隐藏文件
该文件不存在
新文件创建成功

遍历目录文件

package com.test;

import java.util.Scanner;
import java.io.File;
import java.io.FilenameFilter;
public class Test
{
	public static void main(String args[])
	{
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入要访问的目录:");
		String s = scanner.nextLine();//读取待访问的目录名
		
		File dirFile = new File(s);//创建目录文件对象
		String[] allresults = dirFile.list();//获取目录下的所有文件名
		for (String name : allresults)
			System.out.println(name);//输出所有文件名
		
		System.out.println("输入文件扩展名:");
		s = scanner.nextLine();
		Filter_Name fileAccept = new Filter_Name();//创建文件名过滤对象
		fileAccept.setExtendName(s);//设置过滤条件
		String result[] = dirFile.list(fileAccept);//获取满足条件的文件名
		for (String name : result)
			System.out.println(name);//输出满足条件的文件名
	}
}
class Filter_Name implements FilenameFilter
{
	String extendName;
	public void setExtendName(String s)
	{
		extendName = s;
	}
	public boolean accept(File dir, String name)
	{//重写接口中的方法,设置过滤内容
		return name.endsWith(extendName);
	}
}

输出:
请输入要访问的目录:
d:
$RECYCLE.BIN
.temp
360Downloads
360Safe
360安全浏览器下载
360驱动大师目录
BaiduNetdiskDownload
Download
hello.txt
QQMusicCache
Software
System Volume Information
wjt
zhandawei
输入文件扩展名:
txt
hello.txt

删除文件和目录

public class DeleteDirectory {
    /**
     * 删除空目录
     * @param dir 将要删除的目录路径
     */
    private static void doDeleteEmptyDir(String dir) {
        boolean success = (new File(dir)).delete();
        if (success) {
            System.out.println("Successfully deleted empty directory: " + dir);
        } else {
            System.out.println("Failed to delete empty directory: " + dir);
        }
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     * @param dir 将要删除的文件目录
     * @return boolean Returns "true" if all deletions were successful.
     *                 If a deletion fails, the method stops attempting to
     *                 delete and returns "false".
     */
    private static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
       //递归删除目录中的子目录下
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空,可以删除
        return dir.delete();
    }
    /**
     *测试
     */
    public static void main(String[] args) {
        doDeleteEmptyDir("new_dir1");
        String newDir2 = "new_dir2";
        boolean success = deleteDir(new File(newDir2));
        if (success) {
            System.out.println("Successfully deleted populated directory: " + newDir2);
        } else {
            System.out.println("Failed to delete populated directory: " + newDir2);
        }     
    }
}

字节流与字符流

字节流

字节输入流的作用是从数据输入源( 例如磁盘、 网络等)获取字节数据到应用程序( 内存)中。 InputStream是一个定义了 Java 流式字节输入模式的抽象类, 该类的所有方法在出错时都会引发一个 IOException 异常。

package com.test;

import java.util.Scanner;
import java.io.IOException;
import java.io.FileInputStream;
public class Test {
	public static void main(String[] args)
	{
		byte[] b=new byte[1024];//设置字节缓冲区
		int n=-1;
		System.out.println("请输入要读取的文件名:(例如:d:\\hello.txt)");
		Scanner scanner =new Scanner(System.in);
		String str=scanner.nextLine();//获取要读取的文件名
		
		try
		{
			FileInputStream in=new FileInputStream(str);//创建字节输入流
			//遇到文尾时返回-1
			while((n=in.read(b,0,1024))!=-1)
			{//读取文件内容到缓冲区,并显示
				String s=new String (b,0,n);
				System.out.println(s);
			}
			//其实也是关闭输入流
			in.close();//读取文件结束,关闭文件
			}
		catch(IOException e)
		{
			System.out.println("文件读取失败");
		}
	}
}

输出:
请输入要读取的文件名:(例如:d:\hello.txt)
d:\hello.txt
Hello Java

OutputStream 是定义了流式字节输出模式的抽象类, 该类的所有方法都返回一个 void 值并且在出错的情况下引发一个IOException 异常。

package com.test;

import java.util.Scanner;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;
public class Test {
	public static void main(String[] args)
	{
		String content;//待输出字符串
		byte[] b;//输出字节流
		FileOutputStream out;//文件输出流
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入文件名:(例如,d:\\hello.txt)");
		String filename=scanner.nextLine();
		File file = new File(filename);//创建文件对象
	
		if (!file.exists())
		{//判断文件是否存在
			System.out.println("文件不存在,是否创建?(y/n)");
			String f =scanner.nextLine();
			if (f.equalsIgnoreCase("n"))
				System.exit(0);//不创建,退出
			else
			{
				try
				{
					file.createNewFile();//创建新文件
				}
				catch(IOException e)
				{
					System.out.println("创建失败");
					System.exit(0);
				}
			}
		}
		
		try
		{//向文件中写内容
			content="Hello";
			//因为是字节流,所以需要将输入的转变成字节的形式
			b=content.getBytes();
			out = new FileOutputStream(file);//建立文件输出流
			out.write(b);//完成写操作
			out.close();//关闭输出流
			System.out.println("文件写操作成功!");
		}
		catch(IOException e)
		{e.getMessage();}
		
		try
		{//向文件中追加内容
			System.out.println("请输入追加的内容:");
			content = scanner.nextLine();
			b=content.getBytes();
			//第二个参数为true表示文件以设置搜索路径模式打开
			out = new FileOutputStream(file,true);//创建可追加内容的输出流
			out.write(b);//完成追加写操作
			out.close();//关闭输出流
			System.out.println("文件追加写操作成功!");
			scanner.close();
		}
		catch(IOException e)
		{e.getMessage();}
	}
}

输出:
请输入文件名:(例如,d:\hello.txt)
d:\hello.txt
文件写操作成功!
请输入追加的内容:
你好
文件追加写操作成功!

字符流

尽管字节流提供了处理任何类型输入输出操作的足够的功能,但他们不能直接操作Unicode字符。字符流层次结构的顶层是Reader和Writer抽象类。
Reader 是专门用于输入数据的字符操作流, 它是一个抽象类,该类的所有方法在出错的情况下都将引发 IOException 异常。
Writer 是定义流式字符输出的抽象类, 所有该类的方法都返回一个 void 值并在出错的条件下引发IOException 异常。

package com.test;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.FileReader;
public class Test
{
	public static void main(String args[ ]) throws IOException
	   {
	        String strLine;
	        String strTest="Welcome to the Java World!";
	        BufferedWriter bwFile=new BufferedWriter(new  FileWriter("demo.txt"));
	        bwFile.write(strTest,0,strTest.length());
	        //清空缓冲区
	        bwFile.flush( );
	        System.out.println("成功写入demo.txt!");
	        BufferedReader bwReader=new BufferedReader(new FileReader("demo.txt"));
	        strLine=bwReader.readLine( );
	        System.out.println("从demo.txt读取的内容为:");
	        System.out.println(strLine);
	    }
}

输出:
成功写入demo.txt!
从demo.txt读取的内容为:
Welcome to the Java World!

文件流和字符缓冲流

文件流

FileReader 类创建了一个可以读取文件内容的 Reader 类。这两个构造方法都能引发一个 FileNotFoundException 异常。
FileWriter 创建一个可以写文件的 Writer 类。它们可以引发 IOException 或 SecurityException 异常。如果试图打开一个只读文件, 将引发一个 IOException 异常。

package com.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
import java.io.InputStream;
import java.io.OutputStream;
public class Test
{
public static void main(String[] args) throws IOException
	{
		Scanner scanner=new Scanner(System.in);
		System.out.println("请输入源文件名和目的文件名,中间用空格分隔");
		String s=scanner.next();//读取源文件名
		String d=scanner.next();//读取目的文件名
		File file1=new File(s);//创建源文件对象
		File file2=new File(d);//创建目的文件对象
		 
		if(!file1.exists())
		{
			System.out.println("被复制的文件不存在");
			System.exit(1);
		}
		
		InputStream input=new FileInputStream(file1);//创建源文件流
		OutputStream output=new FileOutputStream(file2);//创建目的文件流
		if((input!=null)&&(output!=null))
		{
			int temp=0;
			while((temp=input.read())!=(-1))
				output.write(temp);//完成数据复制
		}
		input.close();//关闭源文件流
		output.close();//关闭目的文件流
		System.out.println("文件复制成功!");
	}
}

字符缓冲流

缓冲流分为缓冲输入流和缓冲输出流,使用缓冲流可以减少应用程序与I/O设备之间的访问次数,提高运输效率;可以对缓冲区中的数据进行按需访问和预处理,增强访问的灵活性。
字节缓冲输入流 BufferedInputStream 类和字符缓冲输入流 BufferedReader 类。
缓冲输出流包括字节缓冲输出流 BufferedOutputStream 类和字符缓冲输出流 BufferedWriter 类。

package com.test;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.BufferedWriter;
public class Test
{
	public static void main(String[] args)
	{
		File file;
		FileReader fin;
		FileWriter fout;
		BufferedReader bin;
		BufferedWriter bout;
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入文件名,例如d:\\hello.txt");
		String filename = scanner.nextLine();
	
		try
		{
			file = new File(filename);//创建文件对象
			if (!file.exists())
			{
				file.createNewFile();//创建新文件
				fout = new FileWriter(file);//创建文件输出流对
			} 
			else
				fout = new FileWriter(file, true);//创建追加内容的文件输出流对象
	
			fin = new FileReader(file);//创建文件输入流
			bin = new BufferedReader(fin);//创建缓冲输入流
			bout = new BufferedWriter(fout);//创建缓冲输出流
			
			System.out.println("请输入数据,最后一行为字符‘0’结束。");
			String str = scanner.nextLine();//从键盘读取待输入字符串
			while (!str.equals("0"))
			{
				bout.write(str);//输出字符串内容
				bout.newLine();//输出换行符
				str = scanner.nextLine();//读下一行
			}
			bout.flush();//刷新输出流
			bout.close();//关闭缓冲输出流
			fout.close();//关闭文件输出流
			System.out.println("文件写入完毕!");
	
			//重新将文件内容显示出来
			System.out.println("文件" + filename + "的内容是:");
			while ((str = bin.readLine()) != null)
				System.out.println(str);//读取文件内容并显示
	
			bin.close();//关闭缓冲输入流
			fin.close();//关闭文件输入流
		}
		catch (IOException e)
		{e.printStackTrace();}
	}
}

运行结果:
请输入文件名,例如d:\hello.txt
d:\hello.txt
请输入数据,最后一行为字符‘0’结束。
fwfwfw
0
文件写入完毕!
文件d:\hello.txt的内容是:
fwfwfw

打印流、数据操作流和系统类System

打印流

Java提供了两种打印流:PrintStream(字节打印流),PrintWriter(字符打印流)。

package com.test;

import java.io.PrintWriter;
public class Test
{
	public static void main(String args[]) 
	      {
	         PrintWriter out = null;
	         // 通过System.out对PrintWriter实例化
	         out = new PrintWriter(System.out);
	        // 向屏幕上输出
	         out. print ("Hello World!");
	         out.close();
	      }
}

输出:
Hello World!

package com.test;

import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;
import java.io.FileWriter;
public class Test
{
	public static void main(String args[])
	      {
	         PrintWriter out = null ;
	         File f = new File("d:\\hello.txt") ;
	         try 
	         {
	            out = new PrintWriter(new FileWriter(f)) ;
	         } 
	         catch (IOException e) 
	         {
	            e.printStackTrace();
	         }
	         // 由FileWriter实例化,则向文件中输出
	         out. print ("Hello World!"+"\r\n");
	         out.close() ;
	      }
}

数据操作流

数据流是Java提供的一种装饰类流,建立在实体流基础上,让程序不考虑所占字节的个数就能正确完成读写操作。数据流类分为DataInputStream类和DataOutputStream类,分别为数据输入流和数据输出流。

package com.test;

import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
import java.io.DataInputStream;
public class Test
{
	public static void main(String args[])
	{
		File file=new File("data.txt");
		try
		{
			FileOutputStream out=new FileOutputStream(file);
			DataOutputStream outData=new DataOutputStream(out);
			outData.writeBoolean(true);
			outData.writeChar('A');
			outData.writeInt(10);
			outData.writeLong(88888888);  
			outData.writeFloat(3.14f);
			outData.writeDouble(3.1415926897);
			outData.writeChars("hello,every one!");
		} 
		catch(IOException e){}
	
		try
		{
			FileInputStream in=new FileInputStream(file);
			DataInputStream inData=new DataInputStream(in);
			System.out.println(inData.readBoolean());//读取boolean数据
			System.out.println(inData.readChar());//读取字符数据
			System.out.println(inData.readInt());    //读取int数据
			System.out.println(inData.readLong());   //读取long数据 
			System.out.println(+inData.readFloat()); //读取float数据
			System.out.println(inData.readDouble()); //读取double数据
			
			char c = '\0';
			while((c=inData.readChar())!='\0')//读入字符不为空
				System.out.print(c);
		}
		catch(IOException e){}
	}
}

输出:
true
A
10
88888888
3.14
3.1415926897
hello,every one!

系统类System

package com.test;

import java.io.FileReader;
import java.io.Reader;
import java.io.File;
public class Test
{
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		File f = new File("d:"+File.separator+"hello.txt");
		Reader input = null;
		input = new FileReader(f);
		char c[] = new char[1024];
		int len = input.read(c);
		input.close();
		System.out.println("内容为:"+new String(c,0,len));
	}
}

输出:
内容为:Hello World!

内存流和扫描流

内存流

字节数组流

package com.test;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
public class Test
{
	public static void main(String[] args) throws Exception 
	{
		String tmp = "abcdefghijklmnopqrstuvwxyz";
		byte[] src = tmp.getBytes();	// src为转换前的内存块
		ByteArrayInputStream input = new ByteArrayInputStream(src);
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		new Test().transform(input, output);
		byte[] result = output.toByteArray();	// result为转换后的内存块
		System.out.println(new String(result));
	}
	public void transform(InputStream in, OutputStream out) 
	{
		int c = 0;
		try 
		{
			while ((c = in.read()) != -1)	// read在读到流的结尾处返回-1
			{
				int C = (int) Character.toUpperCase((char) c);
				out.write(C);
			}
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
}

输出:
ABCDEFGHIJKLMNOPQRSTUVWXYZ

字符数组流
( 1) CharArrayReader 实际上是通过字符数组保存数据的。
( 2) 在构造函数中有 buf, 通过 buf 来创建对象。
( 3) read()函数读取下一个字符。

package com.test;

import java.io.CharArrayReader;
import java.io.IOException;
public class Test
{
    private static final int LEN = 5;
    // 对应英文字母“abcdefghijklmnopqrstuvwxyz”
    private static final char[] ArrayLetters = new char[] {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t',    'u','v','w','x','y','z'};

    public static void main(String[] args) {
        tesCharArrayReader() ;
    }
    /**
     * CharArrayReader的API测试函数
    */
    private static void tesCharArrayReader() {
        try {
            // 创建CharArrayReader字符流,内容是ArrayLetters数组
            CharArrayReader car = new CharArrayReader(ArrayLetters);
            // 从字符数组流中读取5个字符
            for (int i=0; i<LEN; i++) {
                // 若能继续读取下一个字符,则读取下一个字符
                if (car.ready() == true) {
                    // 读取“字符流的下一个字符”
                    char tmp = (char)car.read();
                    System.out.printf("%d : %c\n", i, tmp);
                }
            }
            // 若“该字符流”不支持标记功能,则直接退出
            if (!car.markSupported()) {
                System.out.println("make not supported!");
                return ;
            }
            // 标记“字符流中下一个被读取的位置”。即--标记“f”,因为因为前面已经读取了5个字符,所以下一个被读取的位置是第6个字符”
            // (01), CharArrayReader类的mark(0)函数中的“参数0”是没有实际意义的。
            // (02), mark()与reset()是配套的,reset()会将“字符流中下一个被读取的位置”重置为“mark()中所保存的位置”
            car.mark(0);
            // 跳过5个字符。跳过5个字符后,字符流中下一个被读取的值应该是“k”。
            car.skip(5);
            // 从字符流中读取5个数据。即读取“klmno”
            char[] buf = new char[LEN];
            car.read(buf, 0, LEN);
            System.out.printf("buf=%s\n", String.valueOf(buf));
            // 重置“字符流”:即,将“字符流中下一个被读取的位置”重置到“mark()所标记的位置”,即f。
            car.reset();
            // 从“重置后的字符流”中读取5个字符到buf中。即读取“fghij”
            car.read(buf, 0, LEN);
            System.out.printf("buf=%s\n", String.valueOf(buf));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出:
0 : a
1 : b
2 : c
3 : d
4 : e
buf=klmno
buf=fghij

字符串流

public class Test
{
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			FileReader fr;
			fr=new FileReader("e:\\test1.txt");
			File file =new File("e:\\test2.txt");
			FileWriter	fos=new FileWriter(file);
			BufferedReader	br=new BufferedReader(fr);
			BufferedWriter bw=new BufferedWriter(fos);
			String str=null;
			while((str=br.readLine())!=null) {
				bw.write(str+"\n");
			}
			br.close();
			bw.close();
		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}

扫描流

可以使用 Scanner 类实现基本的数据输入, 其中最简单的方法就是直接使用 Scanner类的 next()方法来实现数据的输入。
但是如果输入的数据中有空格,而输出的数据只有空格之前的那一段,因为Scanner类将空格当成了分隔符。

public class Test
{
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan=null;
		File f=new File("E:"+File.separator+"test.txt");
		try {
			scan=new Scanner(f);
		}catch (Exception e) {
			// TODO: handle exception
		}
		StringBuffer str=new StringBuffer();
		while(scan.hasNext()) {
			str.append(scan.next()).append("\n");
		}
		System.out.println("文件内容为:\n"+str);
	}
}

过滤器流

基本输入流只能读取字节以及字符,但是过滤器流能够读取整数值,双精度值以及字符串。

对象序列化

对象序列化指的是把一个对象变成二进制的数据流的一种方法, 通过对象序列化可以方便地实现对象的传输或者存储。要实现对一个类的对象序列化处理, 则对象所在的类就必须实现 Serializable 接口。

实现序列化就是使用对象输出流输出序列化对象, 而反序列化就是使用对象输入流输入对象。

package com.test;

import java.io.File;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
public class Test {
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		File f = new File("d:"+File.separator+"hello.txt");
		ObjectOutputStream oos=null;
		OutputStream	out = new FileOutputStream(f);
		oos = new ObjectOutputStream(out);
		oos.writeObject(new Person("张三",30));
		oos.close();
	}
}
 class Person implements Serializable{
	private	String	name;
	private	int		age;
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	public String	toString() {
		return	"姓名:"+this.name+";年龄:"+this.age;
	}
}

package com.test;

import java.io.File;
import java.io.ObjectInputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.Serializable;
public class Test {
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		File f = new File("d:"+File.separator+"hello.txt");
		ObjectInputStream ois=null;
		InputStream input = new FileInputStream(f);
		ois = new ObjectInputStream(input);
		Object obj = ois.readObject();
		ois.close();
		System.out.println(obj);
	}
}
class Person implements Serializable{
	private	String	name;
	private	int		age;
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	public String	toString() {
		return	"姓名:"+this.name+";年龄:"+this.age;
	}
}

输出:
姓名:张三;年龄:30

transient 关键字

Serializable 接口实现的操作实际上是将一个对象中的全部属性序列化, 当进行序列化操作时, 如果一个对象中的某个属性不希望被序列化, 则可以使用关键字 transient 声明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值