1.定义:文件和文件夹都是用File代表。
2.创建一个文件对象
使用绝对路径或者相对路径创建File对象。
package file;
import java.io.File;
public class TestFile {
public static void main(String[] args) {
// 绝对路径
File f1 = new File("d:/LOLFolder");
System.out.println("f1的绝对路径:" + f1.getAbsolutePath());
// 相对路径,相对于工作目录,如果在eclipse中,就是项目目录
File f2 = new File("LOL.exe");
System.out.println("f2的绝对路径:" + f2.getAbsolutePath());
// 把f1作为父目录创建文件对象
File f3 = new File(f1, "LOL.exe");
System.out.println("f3的绝对路径:" + f3.getAbsolutePath());
}
}
package file;
import java.io.File;
import java.util.Date;
public class TestFile {
public static void main(String[] args) {
File f = new File("d:/LOLFolder/LOL.exe");
System.out.println("当前文件是:" +f);
//文件是否存在
System.out.println("判断是否存在:"+f.exists());
//是否是文件夹
System.out.println("判断是否是文件夹:"+f.isDirectory());
//是否是文件(非文件夹)
System.out.println("判断是否是文件:"+f.isFile());
//文件长度
System.out.println("获取文件的长度:"+f.length());
//文件最后修改时间
long time = f.lastModified();
Date d = new Date(time);
System.out.println("获取文件的最后修改时间:"+d);
//设置文件修改时间为1970.1.1 08:00:00
f.setLastModified(0);
//文件重命名
File f2 =new File("d:/LOLFolder/DOTA.exe");
f.renameTo(f2);// renameTo方法用于对物理文件名称进行修改,但是并不会修改File对象的name属性。
System.out.println("把LOL.exe改名成了DOTA.exe");
System.out.println("注意: 需要在D:\\LOLFolder确实存在一个LOL.exe,\r\n才可以看到对应的文件长度、修改时间等信息");
}
}
package file;
import java.io.File;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) throws IOException {
File f = new File("d:/LOLFolder/skin/garen.ski");
// 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
f.list();
// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
File[] fs= f.listFiles();
// 以字符串形式返回获取所在文件夹
f.getParent();
// 以文件形式返回获取所在文件夹
f.getParentFile();
// 创建文件夹,如果父文件夹skin不存在,创建就无效
f.mkdir();
// 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹
f.mkdirs();
// 创建一个空文件,如果父文件夹skin不存在,就会抛出异常
f.createNewFile();
// 所以创建一个空文件之前,通常都会创建父目录
f.getParentFile().mkdirs();
// 列出所有的盘符c: d: e: 等等
f.listRoots();
// 刪除文件
f.delete();
// JVM结束的时候,刪除文件,常用于临时文件的删除
f.deleteOnExit();
}
}
4.练习
package file;
import java.io.File;
//遍历文件夹
public class TestFile04 {
public static void main(String[] args) {
File f = new File("c:\\Windows");
// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
File[] fs= f.listFiles();
File max = null;
File min = null;
// 取出一个字节大小大于0的文件,用于作为判断最大或最小初始文件
for(File FS : fs) {
if(f.length() != 0) {
max = FS;
min = FS;
break;
}
}
for(int i=0;i<fs.length;i++){
if(fs[i].length()>0&&fs[i].isDirectory()==false){
if(fs[i].length()>max.length()){
max=fs[i];
}
if(fs[i].length()<min.length()){
min=fs[i];
}
}
}
System.out.println("最大的文件是"+max+",其大小是"+max.length()+"字节");
System.out.println("最小的文件是"+min+",其大小是"+min.length()+"字节");
}
}
package file;
import java.io.File;
public class AtWill {
public static void main(String[] args) {
File f = new File("c:\\Windows");
File[] fs= f.listFiles();
show(fs);
}
public static void show(File dir[]) {
if (dir == null) {
return;
} else {
for (File fi : dir) {
if (fi.isDirectory()) {
show(fi.listFiles());
}
if (fi.isFile()) {
System.out.println(fi.getName());
}
}
}
}
}
注:输出所有文件,问题怎么求最大最小?
package file;
import java.io.File;
public class AtWill {
static File max = null;
static File min = null;
public static void main(String[] args) {
File f = new File("D:\\LOLFolder");
File[] fs= f.listFiles();
// 取出一个字节大小大于0的文件,用于作为判断最大或最小初始文件
for(File FS : fs) {
if(f.length() != 0) {
max = FS;
min = FS;
break;
}
}
show(fs);
System.out.println("最大的文件是"+max+",其大小是"+max.length()+"字节");
System.out.println("最小的文件是"+min+",其大小是"+min.length()+"字节");
}
public static void show(File dir[]) {
if (dir == null) {
return;
} else {
for (File fi : dir) {
if (fi.isDirectory()) {
show(fi.listFiles());
}
if (fi.isFile()) {
System.out.println("文件名:"+fi.getName()+" 大小:"+fi.length());
if(fi.length()>0&&fi.length()<min.length()){
min=fi;
}
if(fi.length()>0&&fi.length()>max.length()){
max=fi;
}
}
}
}
}
}
1.定义:流(Stream)就是一系列的数据。
当不同的介质之间有数据交互的时候,JAVA就使用流来实现。
数据源可以是文件,还可以是数据库,网络甚至是其他的程序
比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream
输出流:OutputStream
2.文件输入流
如下代码,就建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)。
目前代码只是建立了流,还没有开始读取。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
File f = new File("d:/lol.txt");
// 创建基于文件的输入流
FileInputStream fis = new FileInputStream(f);
// 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.文件输出流
public class TestStream {
public static void main(String[] args) {
try {
File f = new File("d:/LOLFolder/DOTA.exe")
FileInputStream fis = new FileInputStream(f);
FileOutputStream fos=new FileOutputStream(f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注:文件放c盘可能拒绝访问。
1.定义:用于以字节的形式读取和写入数据。
2.ASCII码
所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。
比如A就对应的数字65,a对应的数字97。不同的字母和符号对应不同的数字,就是一张码表。
ASCII是这样的一种码表。 只包含简单的英文字母,符号,数字等等。 不包含中文,德文,俄语等复杂的。
字符 十进制数字 十六进制数字
! 33 21
" 34 22
# 35 23
$ 36 24
% 37 25
& 38 26
' 39 27
( 40 28
) 41 29
* 42 2A
+ 43 2B
, 44 2C
- 45 2D
. 46 2E
/ 47 2F
0 48 30
1 49 31
2 50 32
3 51 33
4 52 34
5 53 35
6 54 36
7 55 37
8 56 38
9 57 39
: 58 3A
; 59 3B
< 60 3C
= 61 3D
> 62 3E
@ 64 40
A 65 41
B 66 42
C 67 43
D 68 44
E 69 45
F 70 46
G 71 47
H 72 48
I 73 49
J 74 4A
K 75 4B
L 76 4C
M 77 4D
N 78 4E
O 79 4F
P 80 50
Q 81 51
R 82 52
S 83 53
T 84 54
U 85 55
V 86 56
W 87 57
X 88 58
Y 89 59
Z 90 5A
[ 91 5B
\ 92 5C
] 93 5D
^ 94 5E
_ 95 5F
` 96 60
a 97 61
b 98 62
c 99 63
d 100 64
e 101 65
f 102 66
g 103 67
h 104 68
i 105 69
j 106 6A
k 107 6B
l 108 6C
m 109 6D
n 110 6E
o 111 6F
p 112 70
q 113 71
r 114 72
s 115 73
t 116 74
u 117 75
v 118 76
w 119 77
x 120 78
y 121 79
z 122 7A
{ 123 7B
| 124 7C
} 125 7D
~ 126 7E
3.以字节流的形式读取文件内容(InputStream)
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
//准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
File f =new File("d:/lol.txt");
//创建基于文件的输入流
FileInputStream fis =new FileInputStream(f);
//创建字节数组,其长度就是文件的长度
byte[] all =new byte[(int) f.length()];
//以字节流的形式读取文件所有内容
fis.read(all);
for (byte b : all) {
//打印出来是65 66
System.out.println(b);
}
//每次使用完流,都应该进行关闭
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.以字节流的形式向文件写入数据(OutputStream)
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据
注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。
但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常
package stream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
// 准备文件lol2.txt其中的内容是空的
File f = new File("d:/lol2.txt");
// 准备长度是2的字节数组,用88,89初始化,其对应的字符分别是X,Y
byte data[] = { 88, 89 };
// 创建基于文件的输出流
FileOutputStream fos = new FileOutputStream(f);
// 把数据写入到输出流
fos.write(data);
// 关闭输出流
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5.练习
写入数据到文件
以字节流的形式向文件写入数据 中的例子,当lol2.txt不存在的时候,是会自动创建lol2.txt文件的。
但是,如果是写入数据到d:/lol/lol2.txt,而目录xyz又不存在的话,就会抛出异常。
那么怎么自动创建xyz目录?
如果是多层目录 d:/lol/abc/def/lol2.txt 呢?
package stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
File f=new File("d:/lol/abc/bcd/lol2.txt");
// 所以创建一个空文件之前,通常都会创建父目录
f.getParentFile().mkdirs();
byte data[] = { 88, 89 };
// 创建基于文件的输出流,向文件写入数据
FileOutputStream fos = new FileOutputStream(f);
// 把数据写入到输出流
fos.write(data);
// 关闭输出流
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class TestStream {
public int count;
//拆分文件
public static void onetozero(File file) {
int size = 1024;//1024字符=1k
if(file.length() == 0) {
System.out.println("文件大小为0,无法拆分。");
return;
}
byte a[] = new byte[(int) file.length()];
try {
FileInputStream fis = new FileInputStream(file);
fis.read(a);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
int sum;//拆分文件总数
if (a.length % size == 0) {
sum = (int) (a.length / size);
}
else {
sum = (int) (a.length / size) + 1;//浮点数转变成整数只保留整数部分
}
for (int i = 0; i < sum; i++) {
String name = file.getName() + "_" + i;
//file.getParent()为父目录
File zerofile = new File(file.getParent(), name);
byte b[];
if (i != sum - 1) {
b = Arrays.copyOfRange(a, size * i, size * (i + 1));
}
else {
b = Arrays.copyOfRange(a, size * (sum - 1), a.length);
}
try {
FileOutputStream fos = new FileOutputStream(zerofile);
fos.write(b);
System.out.println("拆分的文件:" + name + "文件长度为:" + zerofile.length());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//合并文件
public static void zerotoone(File file) {
int size = 1024;//1024字符=1k
if(file.length() == 0) {
System.out.println("文件大小为0,无法拆分。");
return;
}
byte aa[] = new byte[(int) file.length()];
try {
FileInputStream fis = new FileInputStream(file);
fis.read(aa);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
int sum;//拆分文件总数
if (aa.length % size == 0) {
sum = (int) (aa.length / size);
}
else {
sum = (int) (aa.length / size) + 1;//浮点数转变成整数只保留整数部分
}
//以上获取文件总数sum--------------------------------
for (int i = 0; i < sum; i++) {
String name = file.getName() + "_" + i;
File zerofile = new File("d:/LOLFolder/", name);
File onefile = new File("d:/LOLFolder/", "test_new");
byte a[] = new byte[(int) zerofile.length()];
try {
FileInputStream fis = new FileInputStream(zerofile);
fis.read(a);
fis.close();
}catch (IOException e) {
e.printStackTrace();
}
try {
//有true不会覆盖已写入的文本,内部使用append
FileOutputStream fos = new FileOutputStream(onefile,true);
fos.write(a);
fos.close();
}catch (IOException e) {
e.printStackTrace();
}
zerofile.delete();//合并后删除该文件
System.out.println(name + "合并入文件:test_new,合并后文件长度为:" + onefile.length());
}
}
public static void main(String args[]) {
/* File file = new File("./test");*/
File file = new File("d:/LOLFolder/test.txt");
System.out.println("获取文件长度为:" + file.length());
//onetozero(file);
zerotoone(file);
}
}
1.关闭流
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
2.在try中关闭
在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
File f = new File("d:/lol.txt");
FileInputStream fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
// 在try 里关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.在finally中关闭
这是标准的关闭流的方式
这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
File f = new File("d:/lol.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally 里关闭流
if (null != fis)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
注:
当fis==null时,执行fis.close()会发生空指针异常。
只有fis!=null,才能执行fis.close()操作。
4.使用try()的方式
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。
对比:
1.定义:专门用于字符的形式读取和写入数据。
2.使用字符流读取文件(Reader)
字符输入流FileReader 是Reader子类,以FileReader 为例进行文件读取。
package stream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
// 准备文件lol.txt其中的内容是AB
File f = new File("d:/lol.txt");
// 创建基于文件的Reader
try (FileReader fr = new FileReader(f)) {
// 创建字符数组,其长度就是文件的长度
char[] all = new char[(int) f.length()];
// 以字符流的形式读取文件所有内容
fr.read(all);
for (char b : all) {
// 打印出来是A B
System.out.println(b);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.使用字符流把字符串写入到文件(Writer)
字符输出流FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件。
package stream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
// 准备文件lol2.txt
File f = new File("d:/lol2.txt");
// 创建基于文件的Writer
try (FileWriter fr = new FileWriter(f)) {
// 以字符流的形式把数据写入到文件中
String data="abcdefg1234567890";
char[] cs = data.toCharArray();
fr.write(cs);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package stream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class TestStream {
//文件加密
public static void encodeFile(File encodingFile, File encodedFile) {
try {
FileReader fr = new FileReader(encodingFile);
char[] in = new char[(int) encodingFile.length()];
fr.read(in);
char[] out = new char[(int) encodingFile.length()];
System.out.println("解密前的内容为:");
for(int i=0; i<in.length; i++) {
if((in[i] >= '0'&& in[i] < '9') || (in[i] >= 'A'&& in[i] < 'Z') || (in[i] >= 'a'&& in[i] < 'z')) {
out[i] = (char) (in[i] +1);
}
/*else if(in[i] == '!'||in[i] == '@'||in[i] == '#'||in[i] == '$'||in[i] == '%'||in[i] == '^'||in[i] == '&'||in[i] == '*'
||in[i] == '('||in[i] == ')'||in[i] == '_'||in[i] == '+') out[i] = in[i];*/
else if(in[i] == '9') out[i] = '0';
else if(in[i] == 'z') out[i] = 'a';
else if(in[i] == 'Z') out[i] = 'A';
else out[i] = in[i];
System.out.print(in[i]+ "");
}
FileWriter fw = new FileWriter(encodedFile);
fw.write(out);
fw.close();//必须关闭,不关闭则在缓冲区中,不会写入到txt,不然使用flush方法
System.out.println();
System.out.println("加密成功,加密后的内容为:");
for(int i=0; i<in.length; i++) {
System.out.print(out[i]+ "");
}
}catch(Exception e){
e.printStackTrace();
}
}
//文件解密
public static void decodeFile(File decodingFile, File decodedFile) {
try {
FileReader fr = new FileReader(decodingFile);
char[] in = new char[(int) decodingFile.length()];
fr.read(in);
char[] out = new char[(int) decodingFile.length()];
System.out.println("解密后的内容为:");
for(int i=0; i<in.length; i++) {
if((in[i] > '0'&& in[i] <= '9') || (in[i] > 'A'&& in[i] <= 'Z') || (in[i] > 'a'&& in[i] <= 'z')) {
out[i] = (char) (in[i] -1);
}
/*else if(in[i] == '!'||in[i] == '@'||in[i] == '#'||in[i] == '$'||in[i] == '%'||in[i] == '^'||in[i] == '&'||in[i] == '*'
||in[i] == '('||in[i] == ')'||in[i] == '_'||in[i] == '+') out[i] = in[i];*/
else if(in[i] == '0') out[i] = '9';
else if(in[i] == 'a') out[i] = 'z';
else if(in[i] == 'A') out[i] = 'Z';
else out[i] = in[i];
//System.out.print(in[i]+ "\t");
System.out.print(out[i]);
}
FileWriter fw = new FileWriter(decodedFile);
fw.write(out);
fw.close();//必须关闭,不关闭则在缓冲区中,不会写入到txt,不然使用flush方法
}catch(Exception e){
e.printStackTrace();
}
//System.out.println();
//System.out.println("解密成功");
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
File f = new File("d:/LOLFolder/lol.txt");
File fen = new File("d:/LOLFolder/lol3.txt");
File fde = new File("d:/LOLFolder/lol4.txt");
encodeFile(f,fen);
System.out.println();
decodeFile(fen,fde);
}
}
1.编码概念
计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字。
就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号。
有的棋盘很小,只能放数字和英文
有的大一点,还能放中文
有的“足够”大,能够放下世界人民所使用的所有文字和符号
如图所示,英文字符 A 能够放在所有的棋盘里,而且位置都差不多
中文字符, 中文字符 中 能够放在后两种棋盘里,并且位置不一样,而且在小的那个棋盘里,就放不下中文
2.常见编码
ISO-8859-1 ASCII 数字和西欧字母
GBK GB2312 BIG5 中文
UNICODE (统一码,万国码)
ISO-8859-1 包含 ASCII
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中
3.UNICODE和UTF
UNICODE:按照UNICODE的方式来存储数据,就会有很大的浪费。
比如在ISO-8859-1中,a 字符对应的数字是0x61
而UNICODE中对应的数字是 0x00000061,倘若一篇文章大部分都是英文字母,那么按照UNICODE的方式进行数据保存就会消耗很多空间
在这种情况下,就出现了UNICODE的各种减肥子编码, 比如UTF-8对数字和字母就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果
UTF-8,UTF-16和UTF-32 针对不同类型的数据有不同的减肥效果,一般说来UTF-8是比较常用的方式
4.Java采用的是Unicode
写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。
而这些中文字符采用的编码方式,都是使用UNICODE. "中"字对应的UNICODE是4E2D,所以在内存中,实际保存的数据就是十六进制的0x4E2D, 也就是十进制的20013。
package stream;
public class TestStream {
public static void main(String[] args) {
String str = "中";
}
}
5.一个汉字使用不同编码方式的表现
以字符 中 为例,查看其在不同编码方式下的值是多少,也即在不同的棋盘上的位置。
package stream;
import java.io.UnsupportedEncodingException;
public class TestStream {
public static void main(String[] args) {
String str = "中";
showCode(str);
}
private static void showCode(String str) {
String[] encodes = { "BIG5", "GBK", "GB2312", "UTF-8", "UTF-16", "UTF-32" };
for (String encode : encodes) {
showCode(str, encode);
}
}
private static void showCode(String str, String encode) {
try {
System.out.printf("字符: \"%s\" 的在编码方式%s下的十六进制值是%n", str, encode);
byte[] bs = str.getBytes(encode);
for (byte b : bs) {
int i = b&0xff;
System.out.print(Integer.toHexString(i) + "\t");
}
System.out.println();
System.out.println();
} catch (UnsupportedEncodingException e) {
System.out.printf("UnsupportedEncodingException: %s编码方式无法解析字符%s\n", encode, str);
}
}
}
6.文件的编码方式-记事本
接下来讲,字符在文件中的保存
字符保存在文件中肯定也是以数字形式保存的,即对应在不同的棋盘上的不同的数字
用记事本打开任意文本文件,并且另存为,就能够在编码这里看到一个下拉。
ANSI 这个不是ASCII的意思,而是采用本地编码的意思。如果你是中文的操作系统,就会使GBK,如果是英文的就会是ISO-8859-1
Unicode UNICODE原生的编码方式
Unicode big endian另一个 UNICODE编码方式
UTF-8 最常见的UTF-8编码方式,数字和字母用一个字节, 汉字用3个字节。
7.文件的编码方式-eclipse
eclipse也有类似的编码方式,右键任意文本文件,点击最下面的"property"
就可以看到Text file encoding
也有ISO-8859-1,GBK,UTF-8等等选项。
其他的US-ASCII,UTF-16,UTF-16BE,UTF-16LE不常用。
8.用FileInputStream 字节流正确读取中文
为了能够正确的读取中文内容
注: 在GBK的棋盘上找到的中字后,JVM会自动找到中在UNICODE这个棋盘上对应的数字,并且以UNICODE上的数字保存在内存中。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
File f = new File("E:\\project\\j2se\\src\\test.txt");
try (FileInputStream fis = new FileInputStream(f);) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
//文件中读出来的数据是
System.out.println("文件中读出来的数据是:");
for (byte b : all)
{
int i = b&0x000000ff; //只取16进制的后两位
System.out.println(Integer.toHexString(i));
}
System.out.println("把这个数字,放在GBK的棋盘上去:");
String str = new String(all,"GBK");
System.out.println(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
9.用FileReader 字符流正确读取中文
FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:
new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));
在本例中,用记事本另存为UTF-8格式,然后用UTF-8就能识别对应的中文了。
解释: 为什么中字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class TestStream {
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("D:\\lol2.txt");
System.out.println("默认编码方式:"+Charset.defaultCharset());
//FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
//而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
try (FileReader fr = new FileReader(f)) {
char[] cs = new char[(int) f.length()];
fr.read(cs);
System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
//并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
10.练习
数字对应的中文:找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字。
转化为字节存入数组,找一个文件(创建项目文本)写入,然后读取文件(UTF-8格式)
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.CharBuffer;
/*
* 找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字
* 1.把这三个字节按字节流写入到编码格式为UTF-8的文件中去
* 2.从文件中按照字符流UTF-8读出这个字符
* 3.把这个字符用String套上,打印出来
* 注意:写入文件是字节,读出来是字符,同时注意读出来时的编码设置
*/
public class EncodingDemo1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] bytes = { (byte) 0xE5, (byte) 0xB1, (byte) 0x8C };
try {
parseChineseFromHex(bytes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void parseChineseFromHex(byte[] bytes) throws IOException {
// TODO Auto-generated method stub
File file = new File("EncodingDemo1.txt");
if (!file.exists()) {
// 如果存在父目录,把上层的目录结构全部补全
if (null != file.getParentFile())
file.getParentFile().mkdirs();
// 创建实体文件
file.createNewFile();
}
// 文件在项目的最外层路径下,而不是包目录下
//System.out.println(file.getAbsolutePath());
// 写入文件中
try (FileOutputStream output = new FileOutputStream(file)) {
output.write(bytes);
}
// 读出来
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) {
// 只有一个字符
char[] cbuf = new char[1];
reader.read(cbuf);
System.out.println(new String(cbuf));
}
}
}
如果用记事本根据UTF-8编码保存汉字就会在最前面生成一段标示符,这个标示符用于表示该文件是使用UTF-8编码的。
找出这段标示符对应的十六进制,并且开发一个方法,自动去除这段标示符
package io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.CharBuffer;
import java.util.Arrays;
/*
* 问题: UTF-8格式保存的文件最前面存在一段标示符BOM,标示它是UTF-8编码的文件
* 找出这段标示符的十六机制,并开发一个方法把这段自动移出
* 思路:1.EncodingDemo1.java中的EncodingDemo1.txt的编码修改为UTF-8
* 2.从EncodingDemo.txt中按照UTF-8格式读出所有字符
* 3.将字符用十六机制表示出来,观察、结果与“ E5 B1 8C ”的不同之处
* 4.把观察的结果记录到byte[]数组中
* 5.把包含BOM的内容byte[]数组去掉上面的观察结果的数组得到移除后的结果
* 6.把移除后的byte[]数组通过int转换成十六进制和打印成String
* 注意:字节转换为int才方便打印成十六进制的格式
* 疑问:若上一个程序结束后直接读取该文件,并不能读到BOM,而必须的手动再修改下该文件的编码格式
* 实际我也只是点击了另存,并没选择它新的编码格式,它默认帮我选择了UTF-8,默认的不是UTF-8?
*结果:经百度发现的确windows简体中文操作系统的ANSI编码指向的是GBK编码
*/
public class EncodingDemo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("EncodingDemo2.txt");
try {
parseBOMFromUTF8File(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
if (null != file.getParentFile())
file.getParentFile().mkdirs();
try {
file.createNewFile();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
private static void parseBOMFromUTF8File(File file) throws FileNotFoundException {
// TODO Auto-generated method stub
try (FileInputStream input = new FileInputStream(file)) {
byte[] content = new byte[(int) file.length()];
input.read(content);
System.out.println(new String(content, "UTF-8"));
System.out.println("编码修改为UTF-8读取到的十六进制为:");
for (byte b : content) {
// 留意int是4个字节,而byte是1个字节
System.out.print(Integer.toHexString(b & 0x000000ff));
}
System.out.println();
byte[] bom = new byte[3];
bom[0] = (byte) 0xef;
bom[1] = (byte) 0xbb;
bom[2] = (byte) 0xbf;
byte[] withoutBOM = removeBOM(content,bom);
System.out.print("去除BOM后的结果为:");
for (byte b : withoutBOM) {
// 注意字节转换为int才方便打印成十六进制的格式
int i = b & 0xff;
System.out.print(Integer.toHexString(i));
}
System.out.println();
System.out.println("去除BOM后的结果为:" + new String(withoutBOM, "UTF-8"));
// String的"e5b18c"怎么解读成byte[] bytes = { (byte) 0xE5, (byte) 0xB1, (byte) 0x8C };
// 答案的方式更合适,还是针对byte[]字符进行操作比较方便
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
// 移除BOM标示符
private static byte[] removeBOM(byte[] content,byte[] bom) {
// TODO Auto-generated method stub
return Arrays.copyOfRange(content, bom.length, content.length);
}
}
1.为什么使用缓存流?
以介质是硬盘为例,字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。
2.使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数据。
package stream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
// 准备文件lol.txt其中的内容是
// garen kill teemo
// teemo revive after 1 minutes
// teemo try to garen, but killed again
File f = new File("d:/lol.txt");
// 创建文件字符流
// 缓存流必须建立在一个存在的流的基础上
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
)
{
while (true) {
// 一次读一行
String line = br.readLine();
if (null == line)
break;
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.使用缓存流写出数据
BufferedReader 缓存字符输出流, 可以一次写出一行数据
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
BufferedReader br=new BufferedReader(new FileReader("data/17软件1班"));
BufferedWriter bw=new BufferedWriter(new FileWriter("data/17软件1班副本本"));
String str="";
while((str=br.readLine())!=null){
System.out.println(str);
bw.write(str+"\n");
}
br.close();
bw.flush();
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
PrintWriter 缓存字符输出流, 可以一次写出一行数据。
package stream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
public static void main(String[] args) {
// 向文件lol2.txt中写入三行语句
File f = new File("d:/lol2.txt");
try (
// 创建文件字符流
FileWriter fw = new FileWriter(f);
// 缓存流必须建立在一个存在的流的基础上
PrintWriter pw = new PrintWriter(fw);
) {
pw.println("garen kill teemo");
pw.println("teemo revive after 1 minutes");
pw.println("teemo try to garen, but killed again");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
PrintWriter和BufferedReader区别:
PrintWriter的print、println方法可以接受任意类型的参数,而BufferedWriter的write方法只能接受字符、字符数组和字符串;
PrintWriter的println方法自动添加换行,BufferedWriter需要显示调用newLine方法;
PrintWriter的方法不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生;
PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush);
PrintWriter的构造方法更广。
PrintWriter和BufferedWriter都是继承java.io.Writer,所以很多功能都一样。不过PrintWriter提供println()方法可以写不同平台的换行符,而BufferedWriter可以任意设定缓冲大小。
OutputStream可以直接传给PrintWriter(BufferedWriter不能接收),如:
PrintWriter out = new PrintWriter(new BufferedOutputStream(new FileOutputStream(“foo.out”)));
或者用OutputStreamWriter来将OutputStream转化为Wrtier.这时就可以用BufferedWriter了。
4.flush
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush。(写入缓冲区,强制写入硬盘)
package stream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
public static void main(String[] args) {
//向文件lol2.txt中写入三行语句
File f =new File("d:/lol2.txt");
//创建文件字符流
//缓存流必须建立在一个存在的流的基础上
try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
pw.println("garen kill teemo");
//强制把缓存中的数据写入硬盘,无论缓存是否已满
pw.flush();
pw.println("teemo revive after 1 minutes");
pw.flush();
pw.println("teemo try to garen, but killed again");
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5.练习-移除注释
设计一个方法,用于移除Java文件中的注释
public void removeComments(File javaFile)
比如,移出以//开头的注释行
File f = new File(“d:/LOLFolder/LOL.exe”);
System.out.println(“当前文件是:” +f);
//文件是否存在
System.out.println(“判断是否存在:”+f.exists());
//是否是文件夹
System.out.println(“判断是否是文件夹:”+f.isDirectory());
注: 如果注释在后面,或者是/**/风格的注释,暂不用处理
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
public void removeComments(File javaFile) {
File newfile=new File(javaFile.getParentFile(),"new"+javaFile.getName());
System.out.println("选中的文件是:"+javaFile.getName());
try(FileReader fReader=new FileReader(javaFile);
BufferedReader bufferedReader=new BufferedReader(fReader);
FileWriter fileWriter=new FileWriter(newfile);
PrintWriter printWriter=new PrintWriter(fileWriter);){
while(true) {
String s=bufferedReader.readLine();
if(s==null) {
break;
}
else {
//判断该行是否以//开头,不是的话写入
if(!s.trim().startsWith("//")) {
printWriter.println(s);
}
}
}
}
catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
File javaFile=new File("D:\\Elipse\\练习-拆分文件\\src\\Main.java");
Main main=new Main();
main.removeComments(javaFile);
}
}
1.分类
DataInputStream 数据输入流
DataOutputStream 数据输出流
2.直接进行字符串的读写
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写
如本例,通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。
注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。
package stream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
write();
read();
}
private static void read() {
File f =new File("d:/lol.txt");
try (
FileInputStream fis = new FileInputStream(f);
DataInputStream dis =new DataInputStream(fis);
){
boolean b= dis.readBoolean();
int i = dis.readInt();
String str = dis.readUTF();
System.out.println("读取到布尔值:"+b);
System.out.println("读取到整数:"+i);
System.out.println("读取到字符串:"+str);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void write() {
File f =new File("d:/lol.txt");
try (
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos =new DataOutputStream(fos);
){
dos.writeBoolean(true);
dos.writeInt(300);
dos.writeUTF("123 this is gareen");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.练习-向文件中写入两个数字,然后把这两个数字分别读取出来。
要求
第一种方式: 使用缓存流把两个数字以字符串的形式写到文件里,再用缓存流以字符串的形式读取出来,然后转换为两个数字。
注: 两个数字之间要有分隔符用于区分这两个数字。 比如数字是31和15,如果不使用分隔符,那么就是3115,读取出来就无法识别到底是哪两个数字。 使用分隔符31@15能解决这个问题。
第二种方式: 使用数据流DataOutputStream向文件连续写入两个数字,然后用DataInpuStream连续读取两个数字。
//缓存流
private static void firstMethod() {
final String filePath = "E://123.txt";
File file = new File(filePath);
try {
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
String str = "31@15";
bw.write(str);
bw.close();
fw.close();
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String str1 = br.readLine();
br.close();
fr.close();
System.out.println("拆解前:"+str1);
String[] str2 = str1.split("@");
System.out.println("拆解后:");
for(String i : str2) {
System.out.println(i);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//数据流
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestData {
public static void main(String[] args) {
write();
read();
}
private static void read() {
File f = new File("d:/test.txt");
try (FileInputStream fis = new FileInputStream(f); DataInputStream dis = new DataInputStream(fis);) {
int i = dis.readInt();
int a = dis.readInt();
System.out.println("读取到整数:" + i);
System.out.println("读取到整数:" + a);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void write() {
File f = new File("d:/test.txt");
try (FileOutputStream fos = new FileOutputStream(f); DataOutputStream dos = new DataOutputStream(fos);) {
dos.writeInt(300);
dos.writeInt(200);
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.定义
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口。
2.序列化一个对象
创建一个Hero对象,设置其名称为garen。
把该对象序列化到一个文件garen.lol。
然后再通过序列化把该文件转换为一个Hero对象
注:把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口
package charactor;
import java.io.Serializable;
public class Hero implements Serializable {
//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
private static final long serialVersionUID = 1L;
public String name;
public float hp;
}
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import charactor.Hero;
public class TestStream {
public static void main(String[] args) {
//创建一个Hero garen
//要把Hero对象直接保存在文件上,务必让Hero类实现Serializable接口
Hero h = new Hero();
h.name = "garen";
h.hp = 616;
//准备一个文件用于保存该对象
File f =new File("d:/garen.lol");
try(
//创建对象输出流
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos =new ObjectOutputStream(fos);
//创建对象输入流
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois =new ObjectInputStream(fis);
) {
oos.writeObject(h);
Hero h2 = (Hero) ois.readObject();
System.out.println(h2.name);
System.out.println(h2.hp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.分类
ObjectInputStream
ObjectOutputStream
import java.io.Serializable;
public class Student implements Serializable{
private static final long serialVersionUID=1L;
private String id;
private String name;
private int score;
public Student(String id, String name, int score) {
super();
this.id = id;
this.name = name;
this.score = score;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String toString() {
return id +" "+ name +" "+ score;
}
}
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputTest {
public static void main(String[] args) {
try {
BufferedReader br=new BufferedReader(new FileReader("data/17软件1班"));
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("data/17软件1班对象"));
String str="";
while((str=br.readLine())!=null){
String[] strs=str.split("\t");
Student stu=new Student(strs[0],strs[1],Integer.parseInt(strs[2]));
//中间过程可以对学号,姓名和分数进行修改
System.out.println(str);
oos.writeObject(stu);
}
br.close();
oos.flush();
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectInputTest {
public static void main(String[] args) {
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("data/17软件1班对象"));
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("data/17软件1班对象2"));
Student student;
/*(Student)ois.readObject()可以理解为一行一个对象,
然后将对象强制转化为Student类型存储在数组对象student中*/
while((student=(Student)ois.readObject())!=null){
student.setScore(student.getScore()+50);
System.out.println(student);
oos.writeObject(student);
}
ois.close();
oos.flush();
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
//e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4.练习-序列化数组
准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
然后把该数组序列化到一个文件heros.lol
接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样
package charactor;
import java.io.Serializable;
public class Hero implements Serializable {
//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
private static final long serialVersionUID = 1L;
public String name;
public float hp;
}
import java.io.*;
public class ObjectStream {
public static void main(String[] args) {
Hero[] h = new Hero[10];
for (int i = 0; i < h.length; i++) {
h[i] = new Hero();
h[i].hp = 100 + i;
h[i].name = "hero" + i;
}
File f = new File("D:/w/w/garen.lol");
try (FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis)) {
oos.writeObject(h);
Hero[] h2 = (Hero[]) ois.readObject();
for (Hero i : h2) {
System.out.println(i.name + ":" + i.hp);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
自动创建有一个属性的类文件。
通过控制台,获取类名,属性名称,属性类型,根据一个模板文件,自动创建这个类文件,并且为属性提供setter和getter。
public class @class@ {
public @type@ @property@;
public @class@() {
}
public void set@Uproperty@(@type@ @property@){
this.@property@ = @property@;
}
public @type@ get@Uproperty@(){
return this.@property@;
}
}
import java.io.*;
import java.lang.reflect.Field;
import java.util.Scanner;
import javax.management.modelmbean.ModelMBean;
import javax.swing.text.ChangedCharSetException;
/**
* 步骤 4 : 练习-自动创建类
* @author 14323
*
*/
public class SystemIn {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String str = "public class @class@ {\r\n" +
" public @type@ @property@;\r\n" +
" public @class@() {\r\n" +
" }\r\n" +
" public void set@Uproperty@(@type@ @property@){\r\n" +
" this.@property@ = @property@;\r\n" +
" }\r\n" +
" \r\n" +
" public @type@ get@Uproperty@(){\r\n" +
" return this.@property@;\r\n" +
" }\r\n" +
"}";
//创建一个模板文件,并创建文件输出流
File file = new File("E://C.class");
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
//将模板写入该文件
bw.write(str);
bw.close();
fw.close();
//调用ScannerByDemo(),获得要替换的数据,并且将各个值依次赋给对应的String
String[] str1 = ScannerByDemo();
String ClassName = str1[0];
String type = str1[1];
String typeName = str1[2];
//更改@Uproperty@所对应的数据首字母为大写
String UtypeName = typeName.substring(0, 1).toUpperCase()+typeName.substring(1);
//创建文件输入流
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
//实例化一个char类型的数组,用于接收br.read()所读到的数据
char[] ch = new char[(int) file.length()];
br.read(ch);
//将ch转化为string类型后开始替换字符串中相应数据
String str2 = new String(ch);
/* String strs="";
String str2="";
while((strs=br.readLine())!=null){
str2+=strs+"\n";
}*/
String str3 = str2.replaceAll("@class@", ClassName)
.replaceAll("@type@", type)
.replaceAll("@property@", typeName)
.replaceAll("@Uproperty@", UtypeName);
//新建同名文件把数据写入(覆盖旧文件)
FileWriter NewFw = new FileWriter(file);
BufferedWriter NewBw = new BufferedWriter(NewFw);
NewBw.write(str3);
NewBw.close();
NewBw.close();
System.out.println("类文件创建完成!");
System.out.println(str3);
}
/**
* 获得要替换的数据,返回值为String数组
* @return
*/
private static String[] ScannerByDemo() {
Scanner input = new Scanner(System.in);
System.out.println("请输入类名:");
String ClassName = input.nextLine();
System.out.println("请输入属性的类型:");
String type = input.nextLine();
System.out.println("请输入属性的名称:");
String typeName = input.nextLine();
return new String[]{ClassName,type,typeName};
}
}
1.复制文件
复制文件是常见的IO操作,设计如下方法,实现复制源文件srcFile到目标文件destFile
public static void copyFile(String srcFile, String destFile){
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class copyFile {
public static void main(String[] args) {
copyFile("before.txt","after.txt");
}
public static void copyFile(String scrFile, String destFile) {
try(FileReader read = new FileReader(scrFile);BufferedReader bread = new BufferedReader(read);
FileWriter write = new FileWriter(destFile);PrintWriter pwrite = new PrintWriter(write,true)){
while(true) {
String string = bread.readLine();
if(string == null)
break;
pwrite.write(string + "\r\n");
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
2.复制文件夹
复制文件夹,实现如下方法,把源文件夹下所有的文件 复制到目标文件夹下(包括子文件夹)
public static void copyFolder(String srcFolder, String destFolder){
}
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) throws IOException {
copyFolder("D:\\LOLFolder\\lol\\abc\\bcd","D:\\LOLFolder\\lol");
}
//复制文件以及文件夹的方法
public static void copyFolder(String srcFolder,String destFolder) throws IOException {
//创建文件对象
File oldfile=new File(srcFolder);
//如果该文件夹为空
if(oldfile.listFiles()==null) {
//在目标文件夹下创建一个名字相同的文件对象
File newfile=new File(destFolder,oldfile.getName());
//在创建文件之前,要先创建父文件夹
newfile.getParentFile().mkdirs();
//然后创建同名文件夹
newfile.mkdir();
//然后返回
return ;
}
//如果文件夹不为空,则遍历该文件夹下的所有文件
else {
File[] filesInOld=oldfile.listFiles();
for (File file : filesInOld) {
//System.out.println(file.getAbsolutePath());
//判断是否是文件
if(file.isFile()) {
//如果是文件,则在目标文件夹下创建一个同名的文件对象
File newf=new File(destFolder,file.getName());
//在创建文件之前,要先创建父文件夹
newf.getParentFile().mkdirs();
//然后新建这个文件
newf.createNewFile();
//然后将文件中的内容进行复制
//注意,这里要传绝对路径
copyFile(file.getAbsolutePath(),newf.getAbsolutePath());
}
//判断是否是文件夹
else if(file.isDirectory()) {
//如果是文件夹,则进行递归
copyFolder(file.getName(),destFolder);
}
}
}
}
//复制文件内容的方法
public static void copyFile(String oldFile,String newFile) throws IOException {
//由于文件夹中可能有字节码文件,比如图像或者视频等等,所以在这里我们使用字节流进行复制,
//如果文件中只有文本文件,那我们就可以使用高效的字符缓冲流进行复制
//创建文件对象
File oldfile=new File(oldFile);
File newfile=new File(newFile);
//注意,这里的形参必须是D:\\TestLoL的绝对路径,不然的话fis对象会在当前项目目录去寻找要复制的文件
//创建字节输入流对象
FileInputStream fis=new FileInputStream(oldfile);
//创建字节输出流对象
FileOutputStream fos=new FileOutputStream(newfile);
//读写数据
byte[] bys=new byte[(int)oldfile.length()]; //定义一个字节数组存储读取到的字节数
int len; //保存实际读取到的字节数
while((len=fis.read(bys))!=-1) {
fos.write(bys, 0, len);
}
//释放资源
fis.close();
fos.close();
}
}
3.查找文件内容
public static void search(File folder, String search);
假设你的项目目录是 e:/project,遍历这个目录下所有的java文件(包括子文件夹),找出文件内容包括 Magic的那些文件,并打印出来。
package file;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
public class SearchContent {
public static void main(String[] args) {
File f = new File("D:\\LOLFolder");
File[] dir= f.listFiles();
Scanner scanner=new Scanner(System.in);
System.out.println("输入你想查找的内容:");
String search=scanner.nextLine();
System.out.printf("\n内容包括%s的那些文件:%n",search);
search(dir,search);
System.out.println("\n查找结束。");
}
public static void search(File dir[], String search){
if (dir == null) {
return;
} else {
for (File fi : dir) {
if (fi.isDirectory()) {
search(fi.listFiles(), search);
}
if (fi.isFile()&&fi.getName().endsWith(".java")) {
try(BufferedReader br = new BufferedReader(new FileReader(fi));){
while(true){
String line=br.readLine();
if(line==null){
break;
}
if(line.contains(search)){
System.out.printf("文件:%s%n",fi.getAbsolutePath());
break;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
1.流关系图
这个图把本章节学到的流关系做了个简单整理
2.其他流
除了上图所接触的流之外,还有很多其他流,如图所示InputStream下面有很多的子类。 这些子类不需要立即掌握,他们大体上用法是差不多的,只是在一些特殊场合下用起来更方便,在工作中用到的时候再进行学习就行了。