@liayun
2016-06-19T16:29:20.000000Z
字数 17822
阅读 1393
java基础
注意:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
先学习一下字符流的特点。
既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件,那么先以操作文件为主来演示。
例,需求:在硬盘上,创建一个文件并写入一些文字数据。
解:
分析:找到一个专门用于操作文件的Writer子类对象——FileWriter,后缀名是父类名,前缀名是该流对象的功能。
创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。其实该步骤就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt"); // 可能会抛出IOException,为了方便,将异常直接抛给JVM
调用write(),将字符串写入到流中
fw.write("abcde");
刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
fw.flush();
关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据,将数据刷到目的地中。和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。
fw.close();
如果想在原有文件上继续加入新的数据呢?
创建一个FileWriter对象时,传递一个true参数,代表不覆盖已有的文件,即在已有文件的末尾处进行数据续写。如:
import java.io.*;
class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("demo.txt", true);
fw.write("nihao\r\nxeixie");
fw.close();
}
}
注意:\r\n
在windows中表示行终止符。
IO异常的处理方式:最后无论如何都应关闭资源,所以应放在finally代码块中。
import java.io.*;
class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
} catch(IOException e) {
System.out.println("catch:"+e.toString());
} finally {
try {
if(fw!=null) // 写在外面也可
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}
例,需求:从硬盘的一个文件中读取内容。
解:
第一种方式读取:
创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
FileReader fr = new FileReader("demo.txt");
调用读取流对象的read()
方法。read()
:一次读取一个字符,会自动往下读。
int ch = 0;
while((ch=fr.read()) != -1) {
System.out.println((char)ch);
}
关闭流资源。
fr.close();
原理:
第二种方式读取:通过字符数组进行读取。
创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
FileReader fr = new FileReader("demo.txt");
定义一个字符数组,用于存储读到的字符,该read(char[])
返回的是读到的字符个数。
char[] buf = new char[1024]; // 字符数组大小为2KB
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, num));
}
关闭流资源。
fr.close();
原理:
练习1、读取一个.java文件,并打印在控制台上。
解:
import java.io.*;
class FileReaderTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("DateDemo.java");
char[] buf = new char[1024];
int num = 0;
while((num=fr.read(buf)) != -1) {
System.out.print(new String(buf, 0, num));
}
fr.close();
}
}
练习2、将c盘一个文本文件复制到d盘中。
解:
分析:复制原理——其实就是将c盘下的文件数据存储到d盘的一个文件中。
步骤:
第一种复制方式:从c盘读一个字符,就往d盘写一个字符。
public static void copy_1() throws IOException {
// 创建目的地
FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");
// 与已有文件关联
FileReader fr = new FileReader("RuntimeDemo.java");
int ch = 0;
while((ch=fr.read()) != -1) {
fw.write(ch);
}
fw.close();
fr.close();
}
第二种复制方式:
public static void copy_2() {
FileReader fr = null;
FileWriter fw = null;
try {
fw = new FileWriter("SystemDemo_copy.txt");
fr = new FileReader("SystemDemo.java");
char[] buf = new char[1024];
int len = 0;
while((len = fr.read(buf)) != -1) {
fw.write(buf, 0, len);
}
} catch(IOException e) {
throw new RuntimeException("读写失败");
} finally {
if(fr != null)
try {
fr.close();
} catch(IOException e) {
}
if(fw != null)
try {
fw.close();
} catch(IOException e) {
}
}
}
原理:
缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符:newLine()
。
创建一个字符写入流对象
FileWriter fw = new FileWriter("buf.txt");
为了提高字符写入流的效率,加入了缓冲技术。只要将需要被提高效率的流对象作为参数,传递给缓冲区的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
for (int x = 1; x < 5; x++) {
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush(); // 记住,只要用到缓冲区,就要刷新。
}
关闭资源,其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
字符读取流缓冲区,该缓冲区提供了一个一次读一行的方法:readLine()
,方便于对文本数据的获取,当返回null时,表示读取到文件末尾。
readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符(行终止符)。
创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("buf.txt");
为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲区对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
调用readLine()
。
String line = null;
while((line = bufr.readLine()) != null) {
System.out.print(line);
}
关闭资源。
bufr.close();
例,需求:明白了BufferReader类中特有方法readLine()的原理后,可以自定义一个类中包含一个功能和readLine()一致的方法,来模拟一下BufferReader。
解:
import java.io.*;
class MyBufferedReader extends Reader {
private Reader r;
MyBufferedReader(Reader r) {
this.r = r;
}
// 可以一次读一行数据的方法
public String myReadLine() throws IOException {
// 定义一个临时容器,原BufferReader封装的是一个字符数组
// 为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变为字符串。
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read()) != -1) {
if(ch == '\r')
continue;
if(ch == '\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length() != 0) // 如果文本数据最后的行终止符故意去掉,那么StringBuilder里面还是有数据的 ,也要给予返回
return sb.toString();
return null; // 如果已到达流末尾,则返回null
}
public void myClose() throws IOException {
r.close();
}
/*
覆盖Reader类中的抽象方法。
*/
public int read(char[] cbuf, int off, int len) throws IOException {
return r.read(cbuf, off, len);
}
public void close() throws IOException {
r.close();
}
}
测试自定义类MyBufferedReader
。
class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt");
MyBufferedReader myBuf = new MyBufferedReader(fr);
String line = null;
while((line=myBuf.myReadLine()) != null) {
System.out.println(line);
}
myBuf.myClose();
}
}
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。
举例来说明装饰设计模式:
class Person {
public void chiFan() {
System.out.println("吃饭");
}
}
class SuperPerson {
private Person p;
SuperPerson(Person p) {
this.p = p;
}
public void superChiFan() {
System.out.println("开胃酒");
p.chiFan();
System.out.println("甜点");
System.out.println("来一根");
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
// p.chiFan();
SuperPerson sp = new SuperPerson(p);
sp.superChiFan();
}
}
假设有这样一个继承体系:
可发现这样的继承体系很臃肿,所以应该换一个继承体系。这样设计类呢?
class MyBufferReader {
MyBufferReader(MyTextReader text) {
}
MyBufferReader(MyMediaReader media) {
}
}
可发现该类扩展性很差,可以找到其参数的共同类型,通过多态的形式,可以提高扩展性。
class MyBufferReader extends MyReader {
private MyReader r;
MyBufferReader(MyReader r) {
}
}
这样,最后的继承体系就是这个样子的:
结论:装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能,所以装饰类和被装饰类通常都是属于一个体系中的。
例,通过缓冲区复制一个.java文件。
解:
分析:readLine()方法的原理:无论是读一行,或者读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read()方法,一次读一个的方法。
import java.io.*;
class CopyTextByBuf {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
String line = null; // 中转站
while((line = bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
} catch(IOException e) {
throw new RuntimeException("读写失败");
} finally {
try {
if(bufr != null)
bufr.close();
} catch(IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(bufw != null)
bufw.close();
} catch(IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
一个带行号的缓冲区。
import java.io.*;
class LineNumberReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("PersonDemo.java");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);
while((line=lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
}
}
练习:模拟一个带行号的缓冲区对象。
解:
class MyLineNumberReader {
private Reader r;
private int lineNumber;
MyLineNumberReader(Reader r) {
this.r = r;
}
public String myReadLine() throws IOException {
lineNumber++; // myReadLine()方法读一次自增一次
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read()) != -1) {
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length() != 0)
return sb.toString();
return null;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public int getLineNumber() {
return lineNumber;
}
public void myClose() throws IOException {
r.close();
}
}
可发现myReadLine()
方法与我们自定义类MyBufferedReader
中的myReadLine()
类似,所以我们可如此做:
class MyLineNumberReader extends MyBufferedReader {
private int lineNumber;
MyLineNumberReader(Reader r) {
super(r);
}
public String myReadLine() throws IOException {
lineNumber++; // myReadLine()方法读一次自增一次
return super.myReadLine();
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public int getLineNumber() {
return lineNumber;
}
}
测试自定义类MyLineNumberReader
:
class MyLineNumberReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("CopyTextByBuf.java");
MyLineNumberReader mylnr = new MyLineNumberReader(fr);
String line = null;
mylnr.setLineNumber(100);
while((line=mylnr.myReadLine()) != null) {
System.out.println(mylnr.getLineNumber()+"::"+line);
}
mylnr.myClose();
}
}
字符流:
字节流:
基本操作与字符流类相同,但它不仅可以操作字符,还可以操作其他媒体文件。
例,向一个文本文件中写入数据。
public static void writeFile() throws IOException {
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());
fos.close();
}
例,从一个文本文件中读取数据。
第一种方式:
public static void readFile_1() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while((ch=fis.read()) != -1) {
System.out.println((char)ch);
}
fis.close();
}
第二种方式:
public static void readFile_2() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
fis.close();
}
第三种方式(不建议使用,因为可能会有内存溢出异常)
public static void readFile_3() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[fis.available()]; // 定义一个刚刚好的缓冲区,不用再循环了。不过慎用!!!
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
练习1、复制一个图片。
解:
思路:
import java.io.*;
class CopyPic {
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream("c:\\2.jpg");
fis = new FileInputStream("c:\\1.jpg");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} catch(IOException e) {
throw new RuntimeException("复制文件失败");
} finally {
try {
if(fis != null)
fis.close();
} catch(IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(fos != null)
fos.close();
} catch(IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
练习2、复制一个MP3文件。
解:
分析:通过缓冲区(BufferedOutputStream/BufferedInputStream),演示MP3的复制。
import java.io.*;
class CopyMp3 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
// 通过字节流的缓冲区完成复制
public static void copy_1() throws IOException {
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\爱的秘密 蓝调口琴曲.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\爱的秘密 蓝调口琴曲_copy.mp3"));
int by = 0;
while((by=bufis.read()) != -1) {
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
练习3、自定义一个类模拟BufferedInputStream,完成一个MP3文件的复制。
解:
分析:
mp3是由二进制数据组成的,如:11111111-1110000000000000000000101010110111010111010010110001。
问题:自定义的myRead()函数为什么会返回int类型,而不直接返回byte类型呢?
分析:
byte: -1 ----> int: -1
11111111(-1)提升为11111111 11111111 11111111 11111111(-1)
11111111(-1)--->提升为一个int类型,那还不是-1吗??是-1的原因是因为在8个1前面补的都是1导致的。那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。怎么补0呢?(&255)
11111111 11111111 11111111 11111111
& 00000000 00000000 00000000 11111111(255)
------------------------------------------
00000000 00000000 00000000 11111111
所以应把11111111(-1)提升为00000000 00000000 00000000 11111111(255),避免返回-1这种情况。
自定义一个MyBufferedInputStream
类,如下:
import java.io.*;
class MyBufferedInputStream {
private InputStream in;
private byte[] buf = new byte[1024*4];
private int pos = 0, count = 0;
MyBufferedInputStream(InputStream in) {
this.in = in;
}
// 一次读一个字节,从缓冲区(字节数组)获取。
public int myRead() throws IOException {
// 通过in对象读取硬盘上数据,并存储到buf中。
if(count == 0) {
count = in.read(buf);
if(count < 0)
return -1;
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b & 255; // 必须&255(0xff),然后再返回
} else if (count > 0) {
byte b = buf[pos];
count--;
pos++;
return b & 0xff; // 必须&255(0xff),然后再返回
}
return -1;
}
public void myClose() throws IOException {
in.close();
}
}
复制MP3:
class CopyMp3 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
copy_2();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
public static void copy_2() throws IOException {
MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\爱的秘密 蓝调口琴曲.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\爱的秘密 蓝调口琴曲_copy_2.mp3"));
int by = 0;
// System.out.println("第一个字节:"+bufis.myRead()); // 第一个字节:-1,因为读到了连续的11111111
while((by=bufis.myRead()) != -1) {
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
}
例,需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印,如果录入的数据是over,那么录入停止。
解:
import java.io.*;
class ReadIn {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true) {
int ch = in.read();
if(ch == '\r')
continue;
if(ch == '\n') {
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0, sb.length()); // 清空缓冲区
} else {
sb.append((char)ch);
}
}
}
}
通过以上的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine()
方法。
能不能直接使用readLine()
方法来完成键盘录入的一行数据的读取呢?
readLine()
方法是字符流BufferedReader类中的方法,而键盘录入的read()方法是字节流InputStream的方法,那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine()
方法呢?此时就需要用到转换流。
例,需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印,如果录入的数据是over,那么录入停止。
解:
import java.io.*;
class TransStreamDemo {
public static void main(String[] args) throws IOException {
// 获取键盘录入对象。
// InputStream in = System.in;
// 将字节流对象转成字符流对象,使用转换流——InputStreamReader
// InputStreamReader isr = new InputStreamReader(in);
// 为了提高效率,将字符流进行缓冲区技术高效操作,使用BufferedReader
// BufferedReader bufr = new BufferedReader(isr);
// 简写格式,键盘录入最常见写法
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
// OutputStream out = System.out; // 屏幕输出
// OutputStreamWriter osw = new OutputStreamWriter(out); // 字符流输出对象转换成字节流输出对象
// BufferedWriter bufw = new BufferedWriter(osw);
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine()) != null) {
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
}
最痛苦的就是流对象有很多,不知道该用哪一个。但通过三个明确来完成:
例1,将一个文本文件中的数据存储到里另一个文件中(复制文件)。
分析:
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中的数据存储到另一个文件中。(复制图片)
解:
import java.io.*;
class MyCopyPicture {
public static void main(String[] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream("c:\\1.jpg"));
bos = new BufferedOutputStream(new FileOutputStream("c:\\ye.jpg"));
// 方式一
/*
int by = 0;
while((by=bis.read()) != -1) {
bos.write(by);
}
*/
// 方式二
byte[] buf = new byte[1024];
int len = 0;
while((len=bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
} catch(IOException e) {
throw new RuntimeException("复制图片失败");
} finally {
try {
if(bis != null)
bis.close();
} catch(IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(bos != null)
bos.close();
} catch(IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
例2,需求:将键盘录入的数据保存到一个文件中。
分析:这个需求中有源和目的都存在,那么分别分析:
设备:键盘。对应的对象是System.in。
不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,转成字符流,按照字符串操作是最方便的,所以既然明确了Reader,那么就将System.in转换成字符流Reader,用到了Reader体系中的转换流,InputStreamReader。
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader bufr = new BufferedReader(isr);
设备:硬盘上的一个文件。使用FileWriter。
FileWriter fw = new FileWriter("c.txt");
BufferedWriter bufw = new BufferedWriter(fw);
扩展一下,想要把录入的数据按照指定的编码表(如UTF-8),将数据存到文件中,怎么办呢?
设备:硬盘上的一个文件,使用FileWriter。但是FileWriter是使用的默认编码表(GBK),但是存储时,需要加入指定的编码表(UTF-8),而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter,而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流,FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"), "UTF-8");
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住,转换流什么时候使用?字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流。
练习:将一个文本数据打印在控制台上。
解:
import java.io.*;
class MyTest {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader("MyCopyPicture.java"));
bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
} catch(IOException e) {
throw new RuntimeException("打印文件到控制台失败");
} finally {
try {
if(bufr != null)
bufr.close();
} catch(IOException e) {
throw new RuntimeException("读取文件关闭失败");
}
try {
if(bufw != null)
bufw.close();
} catch(IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
System类中的字段:in
,out
,它们各代表了系统标准的输入和输出设备,默认输入设备是键盘,输出设备是显示器。
可通过System类的setIn
,setOut
方法对默认设备进行改变,不建议使用。
System.setIn(new FileInputStream("PersonDemo.java")); // 将源改成文件PersonDemo.java
System.setOut(new PrintStream("zzz.txt")); // 将目的改成文件zzz.txt
log4j:记录日志信息的一个工具。
import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfo {
public static void main(String[] args) throws IOException {
try {
int[] arr = new int[2];
System.out.println(arr[3]);
} catch(Exception e) {
try {
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
PrintStream ps = new PrintStream("exception.log");
// ps.write(d.toString().getBytes());
ps.println(s);
System.setOut(ps);
} catch(IOException ex) {
throw new RuntimeException("日志文件创建失败");
}
e.printStackTrace(System.out);
}
}
}
import java.util.*;
import java.io.*;
class SystemInfo {
public static void main(String[] args) throws IOException {
Properties prop = System.getProperties();
// System.out.println(prop);
prop.list(new PrintStream("sysinfo.txt"));
}
}
通过sysinfo.txt文本文件可以知道平台默认的字符集,即默认字符编码是GBK。