Java输入输出

输入、输出是所有程序必须的部分,使用输入机制,运允许程序读取外部数据(包括来自磁盘,光盘等存储设备的数据)、用于输入数据;使用输出机制,允许程序记录运行状态,将程序数据输出到磁盘,光盘等存储设备中。

File类

File类是java.io包下代表与平台无关的文件和目录,不管是文件还是目录都使用File类来操作,File不能访问文件本身内容。如果需要访问文件内容,则需要使用输入、输出流。

访问文件名相关的方法

(1)String   getName():返回此File对象的所表示的文件名或路径名(如果是路径,则返回最后一级子路径名)。

(2)String   getPath():返回此File对象所对应的路径名。

(3)File   getAbsoluteFile():返回此File对象所对应的绝对路径所对应的File对象。

(4)String   getAbsolutePath():返回此File对象所对应的绝对路径名。

(5)String   getParent():返回此File对象对应目录(最后一级子目录)的父目录名。

(6)boolean   renameTo(File  newName):重命名此File对象对应的文件或目录。

文件检测相关的方法

(1)boolean   exists():判断File对象对应的文件或目录是否存在。

(2)boolean   canWrite():判断File对象对应的文件和目录是否可写。

(3)boolean   canRead():判断File对象对应的文件和目录是否可读。

(4)boolean   isFile():判断File对象所对应的是否是文件,不是目录。

(6)boolean   isAbsolute():判断File对象所对应的文件或目录是否是绝对路径。

获取常规文件信息

(1)long   lastModified():返回文件的最后修改时间。

(2)long   length():返回文件内容的长度。

文件操作的相关方法

(1)boolean   createNewFile():当此File对象所对应的文件不存在时,该方法将新建一个该File对象所指定的新文件。

(2)boolean   delete():删除File对象所对应的文件或路径。

(3)static  File   createTempFile(String  prefix,String  suffix):在默认临时文件目录中创建一个临时的空文件,使用给定前缀、系统生成的随机数和给定后缀作文文件名。

(4)static  File   createTempFile(String  prefix,String  suffix,  File  directory):在directory所指定的目录中创建一个临时的空文件,使用给定前缀、系统生成的随机数和给定后缀作文文件名。

(5)void    deleteOnExit():注册一个删除钩子,指定当Java虚拟机退出时,删除File对象所对应的文件和目录。

目录操作的相关方法

(1)boolean   mkdir():试图创建一个File对象所对应的目录。

(2)String[ ]   list():列出File对象的所有子文件名和路径名。

(3)File[ ]    listFiles():列出File对象的所有子文件和路径。

(4)static   File()   listRoots():列出系统所有的根路径。


文件过滤器

在File的lit方法中可以接受一个FilenameFilter参数,通过该参数可以只列出符合条件的文件。

FilenameFilter接口包含一个accept(File  dir,String  name)方法,该方法将依次对指定File的所有子目录、子文件夹进行迭代,如果返回true,则list方法会列出该子目录或子文件夹。

public class FilenameFilterTest {

	public static void main(String[] args) {
		File file = new File(".");
		String[] namelist = file.list(new MyFilenameFilter());
		for (String name : namelist) {
			System.out.println(name);
		}
	}
}
class MyFilenameFilter implements FilenameFilter {

	@Override
	public boolean accept(File dir, String name) {
		// TODO Auto-generated method stub
		// 如果文件名以.java结尾,或者文件对象是一个路径,返回true
		return name.endsWith(".java") || new File(name).isDirectory();
	}

}


Java的IO流

Java中把不同的输入/输出源(键盘,文件,网络连接等)抽象表示为“流”,通过流的方式允许java程序使用相同的方式来访问不同的输入/输出源。

流的分类:

按流的流向划分:分为输入流和输出流。(这里的输入,输出在从程序运行所在的内存角度来划分)

输入流:只能从中读取数据,而不能向其写入数据。

输出流:只能向其写入数据,而不能从中读取数据。
Java的输入流主要由InputStream和Reader作为基类,而输出流则是主要由OutputStream和Writer作为基类。

字节流和字符流

字节流和字符流区别非常简单,它们的用法基本完全一样,区别在于字节流和字符流所操作的数据单元不同:字节流操作的最小数据单元是8为的字节,而字符流操作的最小数据单元是16位的字符。字节流主要由InputStream和OutputStream作为基类,而字符流则主要由Reader和Writer作为基类。

节点流和处理流

节点流输入输出时,程序直接连接到实际的数据源,和实际的输入/输出节点连接。-------低级流

处理流则是用于对一个已经存在的流进行连接或封装,通过封装后流来实现数据读/写功能。------高级流

InputStream和Reader

InputStream和Reader是所有输入流的基类,它们将是所有输入流的模版。

InputStream中三个方法:

(1)int    read():从输入流中读取单个字节,返回所读取的字节数据。

(2)int    read(byte[] b):从输入流中读取最多个b.length个字节的数据,并将其存储在字节数组b中,返回时间读取的字节数。

(3)int    read(byte[] b ,int off,int len):从输入流中读取len字节的数据,并将其存储在数组b中,放入b数组中时,并不是从数组起点开始,而是从off位置开始。

Reader中的三个方法。

(1)int    read():从输入流中读取单个字符,返回所读取的字符数据。

(2)int    read(char[] b)):从输入流中读取最多个b.length个字符的数据,并将其存储在字符数组b中,返回时间读取的字符数。

(3)int    read(char[] b ,int off,int len):从输入流中读取len字符的数据,并将其存储在数组b中,放入b数组中时,并不是从数组起点开始,而是从off位置开始。

InputStream和Reader还支持如下机构方法来移动记录指针:

(1)void   mark( int   readAheadLimit):在记录指针当前位置记录一个标记。

(2)boolean markSupported():判断此输入流是否是支持mark操作,即是否支持记录标记。

(3)void   reset():将此流的记录指针重新定位到上一次记录表标记的位置。

(4)long  skip(long n):记录指针向前移动n个字节或字符。


OutputStream和Writer

OutputStream和Writer提供如下三个方法:

(1)void  write(int  c):将指定的字节/字符输出到输出流中。

(2)void  write(byte[ ]/char[ ]  buf):将字节数组/字符数组中的数据输出到指定的输出流中。

(3)void  write(byte[ ]/char[ ]  buf,int off, int len):将字节数组/字符数组中从off位置开始,长度为len的字节和字符输出到指定的输出流中。

因为字符流直接可以字符作为操作单位,Writer还包括如下两个方法

(1)void   write(String  str):将str字符串中包含的字符输出到指定的输出流中。

(2)void   write(String  str,int off ,int  len):将str字符串中从off位置开始,长度为len的字符输出到指定的输出流中。


输入/输出流体系

处理流的方法

处理流典型的思路:使用处理流来包装节点流,程序通过处理流来执行输入/输出功能,让节点流与底层的I/O设备、文件交互。当我们使用处理流来包装底层节点流之后,关闭输入/输出资源时,只要关闭最上层的处理流即可,关闭上层的处理流时,系统会自动关闭被该处理流包装的节点流。

Java输入/输入流体系中常用的流分类:

通常来说,我们认为字节流的功能比字符流功能强大,因为计算机里所有的数据都是二进制的,而字节流可以处理所有的二进制文件,但如果我们使用字节流来处理文本文件,我们需要使用合适的方式把这些字节转换成字符,这就增加了编程的复杂度。所有通常有一个规则:如果需要进行输入/输出的内容是文本内容,则应该考虑使用字符流,如果需要进行输入/输出的是二进制内容,则考虑使用字节流。


转换流

输入/输出流体系中还提供了两个转换流,这两个转换流由来实现字节流转换成字符流。其中InputStreamReader将字节输出流转换为字符输出流,OutputStreamWriter将字节输出流转换成字符输出流。


重定向标准输入/输出

Java的标准输入/输出分别是通过System.in和System.out来代表,默认情况下它们分别代表键盘和显示器。

System类提供三个重定向标准输入/输出的方法:

(1)static   void   setErr(PrintStream  err):重定向 “标准”错误输出流。

(2)static   void   setIn(InputStream  in):重定向 “标准”输入流。

(3)static   void   setOut(PrintStream   out):重定向 “标准”输出流。

经典实例:

public class RedirectOutTest {

	public static void main(String[] args) {
		PrintStream ps = null;
		try {
			//创建PrintStream输出流
			ps = new PrintStream(new FileOutputStream("d:\\test.txt"));
			//将标准输出重定向到ps输出流
			System.setOut(ps);
			//向标准输出输出字符串
			System.out.println("测试输出流");
			System.out.println("smarhit company");
			//向标准输出流输出一个对象。
			System.out.println(new RedirectOutTest());
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (ps != null) {
				ps.close();
			}
		}

	}
}
public class RedirectInTest {

	public static void main(String[] args) {

		FileInputStream fis = null;
		try {
			fis = new FileInputStream("D:\\test.txt");
			//将标准输入重定向到fis输入流
			System.setIn(fis);
			//使用System.in创建Scanner对象,用于获取标准输入
			Scanner sc = new Scanner(System.in);
			//把回车作为分隔符
			sc.useDelimiter("\n");
			//判断是否还有下一个输入项
			while (sc.hasNext()) {
				// 键盘输入的内容是:测试输出流
				// 键盘输入的内容是:smarhit company
				// 键盘输入的内容是:com.smarhit.io.RedirectOutTest@1fc4bec
				System.out.println("键盘输入的内容是:" + sc.next());

			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

RandomAccessFile

RandomAccessFile类支持随机访问的方式,程序可以直接跳转到文件的任意地方来读写数据,这是因为RandomAccessFile允许自由定位文件记录指针。

RandomAccessFile两个操作文件记录指针的方法:

(1)long   getFilePointer():返回文件记录指针的当前位置。

(2)void    seek(long  pos):将文件记录指针定位到pos位置。

RandomAccessFile既可以读文件,也可以写文件,所以包含了InputStream和三个read方法和OutputStream的三个wirte方法。除此在外,RandomAccessFile还包含了系列的rendXxx和writeXxx方法来完成输入,输出。

RandomAccessFile类提供了两个构造器,一个使用File参数来指定文件本身,一个使用String参数来指定文件名,除此之外,创建RandomAccessFile对象还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,

mode的四个值:

(1)"r":以只读方式打开指定文件。

(2)"rw":以读取、写入方式打开指定文件。

(3)"rws":以读取、写入方式打开指定文件。相对应"rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。

(4)"rwd":以读取、写入方式打开指定文件。相对应"rw"模式,还要求对文件内容的每个更新都同步写入到底层存储设备。

经典实例:

public class RandomAccessFileTest {

	public static void main(String[] args) {
		RandomAccessFile raf = null;
		try {
			//以只读方式打开一个RandomAccessFile对象
			raf = new RandomAccessFile("D:\\test.txt", "r");
			System.out.println("RandomAccessFileTest的文件指针的初始位置:"
					+ raf.getFilePointer());
			//移动raf的文件记录指针的位置
			raf.seek(10);
			//raf.write("追加内容!\r\n".getBytes())     将内容追加到test.txt文件中
			byte[] bbuf = new byte[1024];
			int hasRead = 0;
			while ((hasRead = raf.read(bbuf)) > 0) {
				System.out.println(new String(bbuf, 0, hasRead));
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (raf != null) {
				try {
					raf.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}
}
RandomAccessFile 依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某个位置开始输入,则新输出的内容覆盖文件中原有的内容,如果需要向指定位置插入内容,程序需要先把插入点后面内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区中的内容追加到文件后面。

经典实例

public class RandomAccessFileInsertContent {

	public static void main(String[] args) {
		insert("D:\\test.txt", 10, "四川成都\r\n");
	}

	public static void insert(String fileName, long pos, String insertContent) {
		RandomAccessFile raf = null;
		try {
			//创建一个临时文件,用来保存插入点后的数据
			File tmp = File.createTempFile("tmp", null);
			FileOutputStream tmpOut = null;
			FileInputStream tmpIn = null;
			tmp.deleteOnExit();
			raf = new RandomAccessFile(fileName, "rw");
			tmpOut = new FileOutputStream(tmp);
			tmpIn = new FileInputStream(tmp);
			raf.seek(pos);
			//-----------------下面代码将插入点后的内容读入到临时文件中保存----------------------------
			byte[] buff = new byte[64];
			int hasRead = 0;
			while ((hasRead = raf.read(buff)) > 0) {
				//向临时文件中写入数据
				tmpOut.write(buff, 0, hasRead);
			}
			//把写入指针重新定位到pos位置
			raf.seek(pos);
			//追加需要插入的内容
			raf.write(insertContent.getBytes());
			//追加临时文件中的内容
			while ((hasRead = tmpIn.read(buff)) > 0) {
				raf.write(buff, 0, hasRead);
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				raf.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值