JavaSE基础:IO

本文详细介绍了Java中的IO流概念及分类,包括字节流、字符流及其常用的子类,如FileWriter、FileReader等。此外,还介绍了缓冲流、装饰设计模式在IO流中的应用,以及如何使用File类进行文件操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

IO流分类

按流向:输入流、输出流;
按数据:字节流,字符流。
基类:
字节流:InputStream;OutPutStream
字符流:Reader;Writer;


字符流

数据的最常见体现形式是文件,先以操作文件为主来演示,需求:在硬盘上创建一个文件,并写入文字数据。
Writer——OutputStreamWriter——FileWriter
方法:
    write(str /字符/字符数组/) 方法:将字符串写入到缓冲
    flush()方法:刷新流对象中的缓冲的数据,将数据刷入到目的地中;
    close()方法:关闭流资源,关闭前刷新流,将数据存入目的地中。
如果文件创建成功,一定要执行close方法关闭资源,需要捕捉IO异常;
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个FileWriter对象
windows下的换行是   \r\n  linux下是\n;


Reader——InputStreamReader——FileReader
方法:
    read(), 从输入流获取一个字符并作为数字返回,读到末尾,返回-1;
    
小程序,读取文件 输出到命令窗口;复制文件。
使用字符数组作为缓冲区,注意捕捉异常 。读写完毕,在finally中关闭流。


——————————————————


缓冲流:提高了对数据的读写效率。
    BufferedWriter
    BufferedReader
缓冲区要结合流才能使用,再流的基础上对流的功能进行了增强。


关闭缓冲区就可以关闭缓冲区中的流对象,只要关闭缓冲区即可。
newLine()方法
BufferedReader  字符读取缓冲流
    readLine()读取一行;


小练习:使用缓冲区复制一个文件。
        自定义读取缓冲区,读取一行的方法。
LineNumberReader


装饰设计模式

    当要对已有的对象进行功能增强时,可以定义一个类,将已有的对象传入,给予已有功能,
    并提供加强功能,那么自定义的该类就称为装饰类。
    BufferReader其实就是装饰设计模式的体现。   readLine方法。
    装饰类通常通过构造方法接收被装饰的对象,并给予被装饰对象提供更强的功能。


装饰模式比继承灵活,避免了继承的臃肿,降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的相同,只不过提供了增强功能,所以装饰类和被装饰类属于一个体系。


字节流

    InputStream
    OutputStream


FileOutputStream fos = new FileOutputStream("xxxx.txt") ;
fos.write("abcdef".getBytes()) ;  //字符串转为字节数组
//不需要刷新缓冲区,就可以写入数据,但是要关闭资源
fos.close() ;


FileInputStream  fis = new FileInputStream("dddd.dd")  ;
byte[] buf = new byte[fis.available()] ;  //available 方法返回下一步可读取的字符数,换行符是两个字符
//返回一个刚刚好的缓冲区,不用循环了,这种方法比较危险,一般定义 byte[1024]
fis.read(buf) ;
System.out.println(new String(buf)) ;
fis.close() ;
————————————————————

缓冲区

    BufferedInputStream
    BufferedOutputStream


标准输入输出

FileInputStream in = System.in ;
int by = in.read();


字节流转换字符流:  

InputStreamReader
    InputStreamReader sdr = new InputStreamReader(in) ;
    BufferedReader br = new BufferedReader(sdr) ;
    br.readline();

字符到字节流的桥梁

OutputStreamWriter
    FileOutputStream  fos = System.out ;
    OutputStreamWriter osw = new OutputStreamWriter(fos) ;
    BufferedWriter bw = new BufferedWriter(osw) ;
    bw.write(str );
    bw.newLine() ; //加上换行
    bw.flush() ; 


键盘录入最常见写法。

    1、键盘录入,输出控制台;
    2、键盘录入,输出文件;
    3、读取文件,输出控制台。


流操作的基本规律:

该用哪一个流对象?    
    1、明确源和目的;
            源:输入流     InputStream    Reader
            目的:输出流    OutputStream    Writer
    2、明确操作的数据是不是纯文本。
            纯文本:字符流    Reader    Writer
            非纯文本:字节流    InputStream    OutputStream
    3、体系明确后,在确定使用那个具体的对象
            通过设备区分:
            源设备:内存,硬盘,键盘
            目的设备:内存,硬盘,控制台




File类

方法:
1、创建:
    boolean creatNewFile();    在指定位置上创建文件,如果文件存在,返回false
        和输出流不同,输出流对象已建立就创建文件,如果文件存在,覆盖。
    static File creatTempFile(xxx, xx);  创建临时文件
    boolean mkdir("xx");  创建目录
    boolean mkdirs("xx\\xx\\xx");  创建多级目录
2、删除
    boolean delete();  删除文件,成功返回true 。    
    deleteOnExit();  退出时删除
3、判断
    boolean exists();  判断是否存在
    boolean isDirectory(File);  判断是否为目录,必须先判断是否存在
    boolean isFile(File);    判断是否为文件,必须先判断是否存在
    boolean isHidden();  判断是否隐藏
    boolean isAbsolute();  判断是相对路径或绝对路径。
4、获取信息
    getName();
    getParent(); //返回绝对路径中的文件父目录
    getPath();
    String  getAbsolutePath();获取绝对路径
    File  getAbsoluteFile();返回对象
    long length();返回占用字节
    long lastModified();获取最后修改时间;
long time = file.lastModified();
Date date = new Date(time);
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
String strTime = df.format(date); 
可以通过独立进程监控修改时间,如果被修改,通知程序加载新文件。   


5、boolean  renameTo(File dest);  重命名; 将文件重命名为dest,类似于剪切。
    
6、List
    static  File[]  listRoots();  列出系统根目录 如C:\   D:\   
    String[]  list(); 返回文件目录下的文件和文件名,,包括隐藏文件(一级目录),如果是文件,返回空,必须是目录。该目录必须存在。
    Stringlist (FilenameFilter ff);  按文件名过滤;
    |---FilenameFilter接口,重写方法 boolean  accept(File dir,String name) ;
    File[]  listFiles();返回当前目录下的文件或目录的对象。
    File[]  listFiles(FileFilter filter);按文件过滤;


练习:删除一个带内容的目录:
在windows中,删除目录是从里面往外面删除的。
public class RemoveDirTest {
	public static void main(String[] args) {
		File dir  = new File("e:\\demodir");
		removeDir(dir);
	}


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


练习:遍历文件目录,将指定格式文件目录存储到一个文本列表。
递归:函数直接或间接的调用自身
public class FileTest {


	public static void main(String[] args) {
		File dir = new File("d:\\java\\workspace");		
		listAll(dir,0);
	}


	public static void listAll(File dir,int level) {
		System.out.println(getSpace(level)+dir.getName());
		//获取指定目录下当前的所有文件夹或者文件对象		
		level++;
		File[] files = dir.listFiles(new FileFilter(){
			@Override
			public boolean accept(File pathname) {				
				return pathname.isDirectory()||pathname.getName().endsWith(".java");
			}			
		});
		
		/*
		FilenameFilter filter = new FilenameFilter(){
			@Override
			public boolean accept(File dir, String name) {
				
				return name.endsWith(".java");
			}			
		};
		filter.accept(dir,file.getName());//过滤的另一种方式
		*/
		
		for(int x=0; x<files.length; x++){			
			if(files[x].isDirectory()){
				listAll(files[x],level);
			}
			else
				System.out.println(getSpace(level)+files[x].getName());
		}	
	}


	private static String getSpace(int level) {		
		StringBuilder sb = new StringBuilder();		
		for(int x=0; x<level; x++){
			sb.append("   ");
		}
		sb.append("|--");		
		return sb.toString();
	}
}


Properties

Properties 是hashTable的子类,具备map集合的特点,键值对是字符串,是集合和IO相结合的容器,可以用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式,也就是键——值;
    load(in); store(out,comments);comments为配置文件的首行说明文字,只能是英文字符


练习题:用于记录应用程序运行次数,如果次数已到,那么给出注册提示。
    需要一个配置文件用于记录软件的使用次数。使用Properties配置文件可以实现应用程序数据的共享。            
public class PropertiesTest {
	public static void main(String[] args) throws IOException  {		
		getAppCount();		
	}	
	public static void getAppCount() throws IOException{		
		//将配置文件封装成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();		
	}
}            





打印流:

print()方法可以将各种数据和数据类型原样打印。不会抛出IOException.
    构造函数可以接受的数据类型,如果目标是输出流,可以加自动刷新标记

PrintStream    字节打印流    
    1、File对象    File
    2、字符串路径    String
    3、字节输出流    OutputStream
PrintWriter    字符打印流
    1、File对象    File
    2、字符串路径    String
    3、字节输出流    OutputStream  
    4、字符输出流    Writer
特殊:write(int)方法:将int最低八位输出




读取键盘:

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

序列输入流

SequenceInputStream(Enmuration<InputStream> en)
构造方法将多个读取流合并为一个读取流。

示例
public class SequenceInputStreamDemo {
	public static void main(String[] args) throws IOException {
		//需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。
		/* 
		Vector<FileInputStream> v = new Vector<FileInputStream>();		
		v.add(new FileInputStream("1.txt"));
		v.add(new FileInputStream("2.txt"));
		v.add(new FileInputStream("3.txt"));
		Enumeration<FileInputStream> en = v.elements();//---Vector的elements()方法返回该集合的枚举
		*/
		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);	//---使用集合工具类的enumeration(Collection col)方法返回枚举.
		/*
		final Iterator<FileInputStream> it = al.iterator();   //---局部内部类只能访问被final修饰的局部变量
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){//---自定义枚举
			@Override
			public boolean hasMoreElements() {				
				return it.hasNext();
			}
			@Override
			public FileInputStream nextElement() {				
				return it.next();
			}			
		};*/		
		SequenceInputStream sis = new SequenceInputStream(en);		
		FileOutputStream fos = new FileOutputStream("1234.txt");		
		byte[] buf = new byte[1024];		
		int len = 0;		
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}		
		fos.close();
		sis.close();		
	}
}




练习切割合并文件:
public class MergeFile {//---合并dir目录下的文件
	public static void main(String[] args) throws IOException {
		File dir = new File("c:\\partfiles");		
		mergeFile(dir);
	}	
	public static void mergeFile(File dir) throws IOException {		//---合并文件
    //获取指定目录下的配置文件对象。
		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=0; 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(new File(dir,filename));		
		byte[] buf = new byte[1024];		
		int len = 0;
		while((len=sis.read(buf))!=-1){
			fos.write(buf,0,len);
		}		
		fos.close();
		sis.close();		
	}
}


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


public class SplitFileDemo {//---切割文件,并将信息保存到配置文件中
	private static final int SIZE = 1024 * 1024;
	public static void main(String[] args) throws Exception {
		File file = new File("c:\\aa.mp3");
		splitFile(file);
	}
	private static void splitFile(File file) throws IOException {
		// 用读取流关联源文件。
		FileInputStream fis = new FileInputStream(file);
		// 定义一个1M的缓冲区。
		byte[] buf = new byte[SIZE];
		// 创建目的。
		FileOutputStream fos = null;
		int len = 0;
		int count = 1;
		/*
		 * 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
		 * 这个信息为了进行描述,使用键值对的方式。用到了properties对象 
		 */
		Properties prop  = new Properties();
		File dir = new File("c:\\partfiles");
		if (!dir.exists())
			dir.mkdirs();
		while ((len = fis.read(buf)) != -1) {
			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
			fos.close();
		}		
		//将被切割文件的信息保存到prop集合中。
		prop.setProperty("partcount", count+"");
		prop.setProperty("filename", file.getName());		
		fos = new FileOutputStream(new File(dir,count+".properties"));		
		//将prop集合中的数据存储到文件中。 
		prop.store(fos, "save file info");
		fos.close();
		fis.close();
	}
}

对象流

ObjectInputStream 对象的反序列化
ObjectOutputStream 对象序列化
对象序列化需要实现 Serializable 接口,可以指定序列化的版本号:
    private static final long serialVersionUID = 1l;
static静态成员不能被序列化。只能序列化堆内存中的数据。
transient修饰符:瞬态化成员变量,使非静态成员不被序列化。


RandomAccessFile 随机访问文件类;

不算IO体系中的子类,直接继承自Object。
具备读写功能,内部封装了一个数组,通过指针对数组中的元素操作,
可以通过getFilePointer获取指针位置,同时根据seek设置指针位置。
原理是其内部封装了字节读取流和输入流。


构造方法只能操作文件。
RandomAccessFile(File ,'r/rw');rw 代表读写模式
应用:断点续传功能


管道流

PipedInputStream / PipedOutputStream 
PipedReader / PipedWriter 
connect(Piped)连接管道流
需要使用多线程操作。

示例
public class PipedStream {
	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){
		this.in = in;
	}
	public void run(){		
		try {
			byte[] buf = new byte[1024];
			int len = in.read(buf);			
			String s = new String(buf,0,len);			
			System.out.println("s="+s);
			in.close();
		} catch (Exception e) {
		}		
	}
}


class Output implements Runnable{
	private PipedOutputStream out;
	Output(PipedOutputStream out){
		this.out = out;
	}
	public void run(){		
		try {
			Thread.sleep(5000);
			out.write("hi,管道来了!".getBytes());
		} catch (Exception e) {
		}
	}
}

可以操作基本数据类型的流对象 

DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。
DataInputStream(InputStream in) 使用指定的底层 InputStream 创建一个 DataInputStream。
写入UTF的方法:writeUTF("数据流");  读取只能使用readUTF();


操作字节数组流

ByteArrayInputStream(byte[] buf) 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
ByteArrayOutputStream() 创建一个新的 byte 数组输出流.通过toByteArray()和toString()获取数据.
close()方法无效;不会产生IOException;
writeTo(OutputStream out);将此 byte 数组输出流的全部内容写入到指定的输出流中。
用流的思想操作数组


操作字符数组
CharArrayReader
CharArrayWriter


操作字符串
StringReader
StringWriter


编码表

String str = new String("呵呵","UTF-8");
byte[] buf = str.getBytes("UTF-8");

示例
public class Test {
	public static void main(String[] args) throws IOException {		
		String str = "ab你好cd谢谢";		
//		int len = str.getBytes("gbk").length;		
//		for(int x=0; x<len; x++){
//			System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByByte(str, x+1));
//		}		
		int len = str.getBytes("utf-8").length;		
		for(int x=0; x<len; x++){
			System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByU8Byte(str, x+1));
		}	
	}
	public static String cutStringByU8Byte(String str, int len) throws IOException {		
		byte[] buf = str.getBytes("utf-8");	
		int count = 0;
		for(int x=len-1; x>=0; x--){  //---判断截取的最后几位是什么字符。
			if(buf[x]<0)
				count++;
			else
				break;
		}		
		if(count%3==0)   //---UTF-8的汉字是3个负数
			return new String(buf,0,len,"utf-8");
		else if(count%3==1)
			return new String(buf,0,len-1,"utf-8");
		else 
			return new String(buf,0,len-2,"utf-8");		
	}


	public static String cutStringByByte(String str,int len) throws IOException{		
		byte[] buf = str.getBytes("gbk");		
		int count = 0;
		for(int x=len-1; x>=0; x--){
			if(buf[x]<0)
				count++;
			else
				break;
		}		
		if(count%2==0)
			return new String(buf,0,len,"gbk");
		else
			return new String(buf,0,len-1,"gbk");
	}
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值