----------- android培训、java培训、期待与您交流! ------------
io流:
用来处理设备之间的数据传输;
java流的分类:
I/O流 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
流操作的基本规律:
流太多,使用哪一个?
一、两个明确来确定使用哪个基类。
1、明确需求的源和目的。
源:用输入流,inputStream、Reader
目的:用输出流,OutputStream、Writer
2、操作的对象是否为纯文本文件
是:用字符流
否:用字节流
二、再通过设备,确定使用哪个具体流对象
内存、硬盘、键盘、控制台。
转换流最大功用:指定编码表
需求:将一个字符串写入指定文件中。
思路:用FileReader和FileWriter
import java.io.*;
public class WriteStrToFile {
public static void main(String[] args) {
//创建文件输出流
FileWriter fw = null;
try {
fw = new FileWriter("G:\\Demo.txt", true);//可以续写
//写字符串到输出流中
fw.write("Hello java.");
//将输出流中的信息“冲刷”到文件中
fw.flush();
} catch (IOException e) {
System.out.println(e.toString());
}
finally {
try {
if(fw != null)
//关闭输出流用到的系统资源
fw.close();
} catch (IOException e) {
System.out.println(e.toString()); }
}
}
}
FileReader读取文本文件并打印到控制台
1、读一个字符打印一个字符
2、将读到的字符存入一个字符数组中,用字符数组构造成字符串,再打印。
为什么read返回下一个数据字节,而返回的是int?
它内部返回数值时&255;防止了文件开始为-1的情况(影响文件结束判断标记)
read提升数据类型为int,然后write再将其强转为byte
需求:将G盘中的一个文本文件复制到E盘
思路:用带有缓冲区的文件流BufferedReader和BufferedWriter来操作
import java.io.*;
public class BufferedWriterDemo {
public static void main(String[] args) throws Exception {
//输入流
BufferedReader br = null;
//输出流
BufferedWriter bw = null;
br = new BufferedReader(new FileReader("G:\\Demo.java"));
bw = new BufferedWriter(new FileWriter("E:\\Demo_copy.java"));
String line = null;
//用字符串变量line记下读取的每行文本
while((line = br.readLine()) != null) {
//读取一行写一行
bw.write(line);
//换行
bw.newLine();
}
//关闭资源,实现开发中要捕捉异常,而且要分别捕捉
br.close();
bw.close();
}
}
LineNumberReader
原理:在BufferedReader的基础上多添加了一个private lineNumber属性
跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)
和 getLineNumber()
,它们可分别用于设置和获取当前行号。
注意没有LineNumberWriter类
需求:复制任意文件(复制后能正常使用)
FileWriter和FileReader对文本文件操作方便,但操作多媒体文件复制后会使文件失效。
public class FileCopy {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("G:\\Demo.java");
FileOutputStream fos = new FileOutputStream("E:\\Demo_copy.java");//文件不存在即创建,会抛FileNotFoundException
byte[] buf = new byte[1024];//定义缓冲区,提高了写效率
while(fis.read(buf) != -1) {
fos.write(buf);
//fos.flush();字节流不需要flush
}
fis.close();
fos.close();
}
}
上面代码还可以用BufferedInputStream和BufferedOutputStream提高效率。\
字节流不需要flush()
字符流需要flush():因为字符流底层还是字节+加缓冲,一个字符=2字节。
通过键盘录入信息,并打印,当遇到over即退出。
import java.io.*;
public class KeyboardEntry {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
try
{
while((line=br.readLine()) != null) {
if("over".equals(line)) {
System.exit(0);
}
System.out.println(line);
}
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
从键盘录入写到文件中去:
//通过键盘录入信息,并写入到文件中,可以追加,当遇到over即退出。
import java.io.*;
public class KeyBoardToFile {
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt", true));
String line = null;
try
{
while((line=br.readLine()) != null) {
if("over".equals(line)) {
System.exit(0);
}
bw.write(line);
bw.newLine();
bw.flush();
}
}
catch (IOException e)
{
System.out.println(e.toString());
}
br.close();
bw.close();
}
}
PrintStream:打印流
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
//用文件记录日记信息
public class PrintStreamException {
public static void main(String[] args) throws IOException {
//记录时间
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
//定义打印流
PrintStream ps = new PrintStream(new FileOutputStream("1.txt", true));
try {
int[] i = new int[3];
System.out.println(i[3]);
} catch(Exception e) {
//输出异常信息到文件中,并在开始处加上分隔线和时间
ps.println("------------------------------------------------");
ps.println(s);//2012-09-01 16:02:48
ps.println(e.toString());//java.lang.ArrayIndexOutOfBoundsException: 3
ps.println(e.getMessage());//3
e.printStackTrace(ps); /* java.lang.ArrayIndexOutOfBoundsException: 3
at Demo.main(Demo.java:19)
*/
}
}
}
读取jvm启动信息:
import java.util.*;
import java.io.*;
class Sysinfo {
public static void main(String[] args) throws Exception{
Properties sysinfo = System.getProperties();
sysinfo.list(new PrintStream("sysinfo.txt"));//将系统信息保存到一个文件中
}
}
File类:
将文件或文件夹封装成对象。
import java.io.*;
import java.util.Arrays;
public class FileDemo {
public static void main(String[] args) throws Exception {
File file = new File("1.txt");
if(!file.exists()) {
//创建文件
file.createNewFile();
}
//删除文件
//file.delete();
//jvm退出时删除文件或目录
//file.deleteOnExit();
//得到全路径
System.out.println(file.getAbsolutePath());
//得到文件名
System.out.println(file.getName());
//是否为目录
System.out.println(file.isDirectory());
//是否为文件
System.out.println(file.isFile());
//是否为隐藏文件
System.out.println(file.isHidden());
//文件内容的长度
System.out.println(file.length());
//是否为绝对路径
System.out.println("是绝对路径?" + file.isAbsolute());
File dir = new File("abc\\cd\\java\\a");
//创建多级文件夹
System.out.println(dir.mkdirs());
//创建单个文件夹
System.out.println(dir.mkdir());
//列出系统根目录
File[] sys = dir.listRoots();
System.out.println(Arrays.toString(sys));
//列出某个目录下的文件和目录名
File dir = new File("c:\\");
String[] files = dir.list();
for(String file : files) {
System.out.println(file);
}
需求:列出目录下的所有目录和文件(包括子目录和子目录中的文件)
import java.io.*;
public class FileAllList {
public static void main(String[] args) {
File dir = new File("C:\\Documents and Settings\\Administrator\\桌面");
listAll(dir, 0);
}
//列出所有文件及目录
public static void listAll(File dir, int level) {
System.out.println(getLevel(level) + dir.getName());//打印目录名
level++; //级数自增
File[] files = dir.listFiles();
for(File file : files) {
if(file.isDirectory()) { //是目录则递归
listAll(file, level);
} else {
System.out.println(getLevel(level) + file.getName());//打印文件名
}
}
}
//添加分级分隔符
public static String getLevel(int level) {
StringBuilder sb = new StringBuilder();
for(int i=0; i<level; i++) {
sb.append("|----");
}
return sb.toString();
}
}
需求:删除一个带内容的目录:
import java.io.*;
public class DirRemover {
public static void main(String[] args) {
File dir = new File("C:\\Documents and Settings\\Administrator\\桌面\\abc");
System.out.println(removeDir(dir));
}
public static boolean removeDir(File dir) {
if(dir.exists()) {
File[] files = dir.listFiles();
for(File file : files) {
if(file.isDirectory()) //是目录递归
removeDir(file);
else {
file.delete();//是文件直接删除
}
}
dir.delete();//最后删除最初指定的目录
return true;
}
return false;
}
}
//需求:从一个磁盘复制一个带内容的文件夹到另一个磁盘中。
import java.io.*;
public class DirctoryCopy {
public static void main(String[] args) {
System.out.println(copyDir("G:\\Code", "E:\\test"));
}
//文件夹复制程序
private static boolean copyDir(String originPath, String destPath) {
//将传进来的路径封装成File对象
File originFile = new File(originPath);
File destFile = new File(destPath);
//若源目录不存在,则返回false,程序结束。
if(!originFile.exists()) {
return false;
}
//若目标目录不存在,则新建目录
if(!destFile.exists()) {
destFile.mkdir();
}
//将源目录内的所有文件及文件夹封装成File对象
File[] files = originFile.listFiles();
for(File file : files) {//遍历每个File对象
if(file.isDirectory()) {
//如果是目录则递归
copyDir(file.getPath(), destPath + "\\" + file.getName());
}
else {
//若是文件则调用文件复制程序来copy文件
copyFile(file.getPath(), destPath + "\\" + file.getName());
}
}
return true;
}
//文件复制程序
private static boolean copyFile(String originFilePath, String destFilePath) {
//用传进来的文件路径封装成File对象
File originFile = new File(originFilePath);
File destFile = new File(destFilePath);
//创建流对象,准备复制
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(originFile);
fos = new FileOutputStream(destFile);
byte[] buf = new byte[1024];
//增加缓冲区。先将数据读到buf数组内,再将buf数组里的有效数据一次性写入目标文件
while(fis.read(buf)!=-1) {
fos.write(buf, 0, buf.length);
}
//捕捉异常
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
} catch (IOException e) {
System.out.println("文件读写错误");
}
//关闭资源
finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
System.out.println("fis关闭失败");
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
System.out.println("fos关闭失败");
}
}
}
return true;
}
}
SequenceInputStream(合并流):能将多个流文件进行连接的高级流
其有个构造方法为:
public SequenceInputStream(Enumeration<? extends InputStream> e)
用到了枚举。
实际操作中可以将流对象存入Vector集合中,再用其方法:
public Enumeration<E> elements(),得到向量中组件的枚举。
文件切割:将数据读到byte[]数组中,数组大小自定义。装满即写入一个文件中,最后文件被分成几部分
文件合并:用到合并流。
ObjectOutputStream和ObjectInputStream:操作对象的流(对象需要实现Serializable接口)
RandomAccessFile:对随机访问文件的读取和写入★★★
内部封装了字节输入流和输出流
有模式r、rw、rws、rwd
该流可以跳过一些字节
使用多线程,就可以实现“跳节”下载
PipedOutputStream(管道流):使得输入流和输出流相接。(需结合线程使用)
DataInputStream:操作基本数据类型
ByteArrayInputStream:操作数组
CharArrayReader:操作字符数组
StringReader:操作字符串
编码:
import java.io.*;
import java.util.Arrays;
public class EncodeStream {
public static void main(String[] args) throws Exception {
OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream("G:\\utf.txt"), "UTF-8");
String str = "你好";
byte[] bGBK = str.getBytes();
//打印“你好”字符串在内存中的字节表示形式
System.out.println(Arrays.toString(bGBK));//[-60, -29, -70, -61]
byte[] bUTF = str.getBytes("UTF-8");
//打印“你好”字符串在内存中的字节表示形式
System.out.println(Arrays.toString(bUTF));//[-28, -67, -96, -27, -91, -67]
os.write(str);
os.close();
}
}
Windows默认编码表为GBK,若文件存入时是按UTF-8编码存,然后用GBK编码表来读就出问题,反之亦然。
GBK一个中文字符用两字节表示,UTF-8中一个中文字符用三个字节表示。
用记事本软件只所以能打开,是因为它根据你存入时用的编码来读取文件,所以会获得正确的显示。
二次编码、解码得到正确结果:
public class EncodeDecode {
public static void main(String[] args) throws Exception {
String str = "你好";
//第二种情况
/*//对字符串用UTF-8编码
byte[] b1 = str.getBytes("UTF-8");
//用了GBK解码
String str1 = new String(b1, "GBK");
System.out.println(str1);//浣犲ソ 三个字符
//再次用GBK编码
byte[] b2 = str1.getBytes("GBK");
//用UTF-8编码
System.out.println(new String(b2, "UTF-8"));//你好 两个字符
*/
//第一种情况
//对字符串用GBK编码
byte[] b1 = str.getBytes("GBK");//
//用ISO8859-1解码
String str1 = new String(b1, "ISO8859-1");
System.out.println(str1);//????
//再次用ISO8859-1编码
byte[] b2 = str1.getBytes("ISO8859-1");
//再次用GBK解码
String str2 = new String(b2, "GBK");
System.out.println(str2);//你好
}
}
第一种情况是编码相似,可反编;第二种情况是第一次编码后的字节数 = “解码表”表示位数的整数倍,可反编。
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有功能并进行功能加强。
所以装饰类和被装饰类属于同一个体系。
继承:
装饰:
装饰比继承灵活,避免了继承体系臃肿,降低了类与类之间的关系。(继承-组合)
----------------------- android培训、java培训、期待与您交流! ----------------------