java基础——String类和IO

字符串

一、字符串操作是计算机程序设计中最常见的行为。因此,我们可以这样说,没有操作过String的人,不能说你是一个合格的开发人员。

二、不可变String

String类总每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。

字符串的最大特点在于:一旦被初始化,就不能被改变。字符串这种常量存在于方法区中。String类复写了Object类中的equals方法,该方法用于判断字符串是否相同。

例子:String s1=“abc”;  //s1是一个类类型 变量,“abc”是一个对象。当调用s1="kk"时,只是s1指向地址变了,s1指向了"kk"这个对象。"abc"这个对象在内存中还存在。

 Stirng s2=new String("abc");

s1和s2有什么区别?s1在内存中只有一个对象,s2在内存中有2个对象(new String()和“abc”)。

s1==s2------false    ------------这是两个对象。

s1.equals(s2)------true-----------String类复写了Object中的equals方法,该方法用于判断字符串是否相同。

三、String类功能操作

1、获取

(1)int length()   String中字符的个数。

(2)char charAt(int index)  获取字符串中指定位置上的某个字符。

(3)int indexOf(int ch)   传入的时ASCII码,返回的时ch在字符串中第一次出现的位置。

(4)int indexOf(int ch,int fromIndex)   获取字符串中某个字符从指定索引开始第一次出现的位置。

(5)int indexOf(String str)  获取指定子字符串在字符串中第一次出现的位置。

(6)int indexOf(String str,int fromIndex)    获取指定子字符串从指定索引开始第一次出现在字符串中的位置。

(7)int lastIndexOf(int ch)    获取指定字符在字符串中最后一次出现的位置。

2、判断-----返回boolean

(1)boolean contains(CharSequence s)     字符串中是否包含某一个子串。

(2)boolean isEmpty()    字符串是否为空。

(3)boolean startsWith(String prefix)   字符串是否以指定前缀开始。

(4)boolean endsWith(String suffix)    字符串是否以指定后缀结束。

(5)boolean equals(Object anObject)   将字符串与指定的字符串比较。

(6)boolean equalsIgnoreCase(String anotherStrnig)   将这个String与另一个String比较,不考虑大小写。

3、类型间转换

(1)char[] toCharArray()    将字符串转换成一个字符数组。

(2)构造方法   String(byte[] bytes)   将指定字节数组转换成字符串。

(3)构造方法   String(char[] value)    将指定字符数组转换成字符串。

(4)byte[] getBytes()    将字符串编码为byte序列,将结果存储到一个新的byte数组中。

(5)static String valueOf(基本数据类型)   将基本数据类型转换为字符串。

4、替换

(1)String replace(char oldChar,char newChar)   将字符串中所有出现的oldChar用newChar替换。

5、切割

(1)String split(String regex)   根据给定正则表达式的匹配拆分此字符串。

6、子串

(1)String subString(int beginIndex)   从指定位置开始,返回一个新的字符串

(2)String subString(int beginIndex,int endIndex)    从指定位置开始到指定位置结束,返回一个新的字符串。(包含头,不包含尾)

7、大小写转换,去除空格,比较

(1)String toUpperCase()    将字符串转换成大写格式

(2)String toLowerCase()    将字符串转换成小写格式

(3)String trim()    去除字符串两端的空格

(4)int compareTo(String anotherString)  按字典顺序比较两个字符串。

四、StringBuffer和StringBuilder

1、StringBuffer是字符串缓冲区,是一个容器。有三个特点:(1)长度可变;(2)可以直接操作多个数据类型;(3)最终会通过toString方法变成字符串。

2、StringBuffer操作

(1)存储

StringBuffer append(数据)  将指定数据插入到StringBuffer的末尾处。

(2)删除

StringBuffer delete(int start,int end)   删除缓冲区中的数据,包含start,不包含end。

StringBuffer deleteCharAt(int index)   删除指定位置处的字符。

(3)获取

char CharAt(int index)   返回StringBuffer指定位置处的char。

int indexOf(String str)

int lastIndexOf(String str)

int length()

String subString(int start)  

(4)修改

StringBuffer replace(int start,int end,String str)   用给定str替换其中的start到end处的字符串。

void setCharAt(int index,char ch)    将指定索引处的字符设置为ch

(5)反转

StringBuffer reverse()    将字符串反转。

(6)void  getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin)    将缓冲区中的指定数据存储到指定数组中。

3、StringBuilder

StringBuffer:线程同步,单线程效率不高。

StringBuilder:线程不同步,不建议用于多线程。   提高效率,简化书写,提高了安全性。

IO流

java语言处理其他设备上所有的数据,对其进行操作就是通过流的方式。java中用于操作流的对象都被封装在IO包中。

1、流按操作数据区分:字节流和字符流。  按流向区分:输入流和输出流。

2、字节流的抽象基类:InputStream和OutputStream  字符流的抽象基类:Reader和Writer。

3、老的I/O流继承结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符,由于Unicode用于字符国际化(Java本身的char也是16位的Unicode),所以添加Reader和Writer继承层次结构就是为了在所有的I/O操作中都支持Unicode。

一、字符流

1、IO流是用于操作数据的,那么数据的最常见体现形式是:文件。先以操作文件来演示:

在JDK API中找到一个专门用于操作文件的Writer子类对象:FileWriter。后缀名是父类名,前缀名是该流对象的功能。

操作:

(1)创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。而且该文件会被创建到指定的目录下,如果该目录下有同名文件,将被覆盖。

如:FileWriter fw=new FileWriter("demo.txt");  将在你所写的java文件当前目录下创建一个demo.txt文件。

(2)调用write方法,将字符串写入到流中。   fw.write("abc");

(3)刷新流对象中的缓冲区中的数据,将数据刷到目的地中。    fw.flush();  将会把abc刷到demo.txt文件中。

(4)关闭流资源。(关闭之前,会刷新一次内部的缓冲区中的数据。)fw.close();

注:close和flush的区别:flush刷新后,流可以继续使用;close刷新后,会将流关闭。

当创建对象时,如果指定创建文件位置不存在,将会发生IOExcpetion,需要对其进行try处理。

FileWriter fw=null;

try{

       fw=newFileWriter("demo2.txt");

       fw.write("abdaef");

}catch(IOException e)

{

       throw new RuntimeException("写入失败!");

}finally{

       try {

              if(fw!=null)

              fw.close();

       } catch(IOException e){

       }

}

当要对文件进行续写时,fw=new FileWriter("demo.txt",true); 传递一个参数,表示不覆盖原有的文件,在已有文件的末尾处进行续写。

2、文本文件读取方式

(1)创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件是已经存在的,如果不存在,会发生FileNotFound异常。

FileReader fr=new FileReader("demo.txt");

(2)调用流读取对象的read方法。

读取方式一:一次读一个:int ch=0;

while(ch!=-1)

{

ch=fr.read();

System.out.println((char)ch);

}

读取方式二:char[] buf=new char[1024];

int num=0;

while((num=fr.read(buf))!=-1)  //public int read(char[] buff)  throws IOException   将字符读入数组。

{

String s=new String(buf,0,num);//将字符数组转换成字符串。

System.out.println(s);

}

3、练习:将c盘一个文本文件复制到D盘

复制原理:其实就是将C盘下的文件数据存储到D盘的一个文件中。

步骤:(1)在D盘创建一个文件,用于存储C盘下文件的数据。

(2)定义读取流和C盘文件相关联。

(3)通过不断的读写完成数据存储。

(4)关闭资源。


4、字符流缓冲区

字符写入流缓冲区

缓冲区的出现提高了对数据的读写速率。所以在创建缓冲区之前,必须要先有流对象。对应类:BufferedWriter和BufferedReader。

只要用到缓冲区,就要记得刷新。其实关闭缓冲区,就是关闭缓冲区中的流对象。

(1)创建一个字符写入流对象。

FileWriter fw=new FileWriter("buf.txt");

(2)创建一个字符写入流缓冲区对象

BufferedWriter bufw=new BufferedWriter(fw);//将需要被提高速率的流对象作为参数传递给缓冲区的构造函数。

(3)调用write方法将数据写入到文件中

bufw.write("abadaf");

(4)刷新缓冲区。

bufw.flush();

(5)关闭缓冲区。

bufw.close();

注:bufw.newLine();这个是一个跨平台的换行符,不论在windows还是Linux中都表示换行。

字符读取流缓冲区

readLine----不包含任何行终止符。

原理:无论是读一行,还是读取多个字符,其实最终都是在硬盘上一个一个读取,最终使用的还是read方法一次读一个的方法。

FileReader fr=new FileReader("a.txt");

BufferedReader bufr=new BufferedReader(fr);

String line=null;

while((line=bufr.readLine())!=null)

{System.out.println(line);}

可以练习用缓冲区技术来复制一个文本文件。

5、装饰设计模式

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供增强功能。那么自定义的该类就称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。

如:自定义一个MyBufferedReader。根据BufferedReader的实现原理来自定义一个MyBufferedReader。

BufferedReader中的readLine方法:读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。


二、字节流

1、InputStream和OutputStream

2、不需要进行flush动作:因为字节流操作的数据的最小单位,字节,所以不需要进行刷流动作。其实字符流底层调用的也是字节流。

3、字节流基本操作和字符流基本操作类似。

写操作:

FileOutputStream fos=new FileOutputStream("fos.txt");

fos.write("abcde".getBytes());

fos.close();

读操作:

方式一:FileInputStream fis=new FileInputStream("fos_copy.txt");

int ch=0;

while((ch=fis.read())!=-1)

{

System.out.println((char)ch); 

}

fis.close();

方式二:FileInputStream fis=new FileInputStream("fos_copy.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();

方法三:FileInputStream fis=new FileInputStream("fos_copy.txt");

byte[] buf=new byte[fis.available()];//int available() 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。

fis.read(buf);

System.out.println(new String(buf));

fis.close();

4、字节流缓冲区

(1)提高了读写效率。

读写特点:read(),会将byte提升为int。write会将int强转为byte。

(2)自定义字节流缓冲区

/*
通过自定义字节流缓冲区演示mp3 的复制,通过缓冲区BufferedOutputStreamBufferedInputStream
*/


5、读取键盘录入

System.out:对应的是标准输出设备,控制台。

System.in:对应的是标准输入设备,键盘。

练习:通过键盘录入数据,当录入一行数据后,就将该数据进行打印。如果录入的数据时over,那么停止录入。


上面的代码其实就是readLine()方法的原理。而readLine方法是字符流的读一行的方法,为此我们需要把字节流转换为字符流。

6、读取转换流

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

BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));

String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line)) break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();

7、流操作基本规律

流对象有很多,不知道该用哪一个。---------------------问题

通过两个来明确:

(1) 明确源和目的

源:输入流   InputStream Reader

目的:输出流 OutputStream Writer

(2) 明确操作的数据是否是纯文本

是:字符流

不是:字节流

(3)当体系明确后,再明确要使用哪个具体的对象。

通过设备来进行区分

源设备:内存,硬盘,键盘

目的设备:内存,硬盘,控制台

8、改变标准输入输出设备

System类中提供了两个方法:System.setIn(源文件) System.setOut(目的文件)

9、异常的日志信息

需求:将异常信息保存在日志文件里。


10、System类中的Properties

Properties prop=System.getProperties();//Properties可以和流相结合
//System.out.println(prop);
prop.list(System.out);//打印信息到控制台
prop.list(new PrintStream("SystemInfo.txt"));
//打印信息到文本文件中。

三、File概述

File类,用来将文件和文件夹封装成对象,方便对文件和文件夹中的属性信息进行操作。

与流的不同:流只能操作数据。

1、FIle常见方法

(1)创建

boolean createNewFile()       由于调用到了底层,所以会产生异常,在指定位置创建文件,如果该文件已经创建,则不创建,返回false

和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,会覆盖

static File createTmpFile(String s1,Strings2)使用给定前缀和后缀创建临时文件

static File createTmpFile(String s1,Strings2,File f)在指定位置使用给定前缀和后缀创建临时文件

(2)删除

boolean delete();

void deleteOnExit();  在退出时删除

(3)判断

canExecute();测试文件是否可执行。

boolean exists():文件是否存在。

mkdir():创建文件夹

mkdirs():创建多级目录

isFile():判断是否是文件

isDirectory():判断是否是目录

isHidden():判断是否是隐藏文件。

(4)获取信息

getName():获取文件名

getParent():返回文件的父目录

getPath():获取抽象路径

getAbsolutePath():获取绝对路径

long lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。

long length(): 返回由此抽象路径名表示的文件的长度。

renameTo(目的地):类似于移动

File[] listRoots():列出所有的盘符

list():返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录

list(FilenameFilter filter):返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。

File[] listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

2、递归---列出指定目录下文件或者文件夹,包含子目录中内容,也就是列出指定目录下所有内容。

public static void listFiles(File dir)
{
File[] files=dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(files[x].isDirectory())
listFiles(files[x]);
else
System.out.println(files[x]);
}
}

递归:函数自身调用自身。递归图解:

递归注意事项:(1)限定递归的条件;(2)限定递归的次数,防止内存溢出。

3、递归应用

需求:将一个指定目录下的java文件的绝对路径,存储到一个文本文件中,建立一个java文件列表文件。

思路:(1)对指定的目录进行递归

(2)获取递归过程中所有的java文件的路径

(3)将这些路径存储到集合中

(4)将集合中的数据写入到一个文件中


四、Propeties对象

它是HashTable的子类,具备了Map集合的特点,而且他里面存储的键值对都是字符串,是集合中和IO技术相结合的集合容器。

特点:可以用于键值对形式的配置文件。那么在加载数据时,需要数据有固定格式:键=值。

如何将流中的数据存储到集合中,想要将info.txt中键值数据存到集合中进行操作。

(1)用一个流和文件相关联

(2)读取一行数据,将该行数据用“=”进行切割

(3)等号左边作为键,右边作为值,存入到Properties集合中即可。

代码实现:

BufferedReader bufr=new BufferedReader(new FileReader("D:\\java0204\\info.txt"));//读取某个文件。

String line=null;

Properties prop=new Properties();
while((line=bufr.readLine())!=null)
{
String[] arr=line.split("=");
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);

Properties有自己的方法:
        load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。

注:properties其实就是Map技术和io技术的集合。键值对数据是map集合,数据以文件形式存储(使用io技术),二者结合就是properties。

五、IO包中的其他类

1、打印流:PrintWriter和PrintStream

(1)字节打印流:PrintStream

构造函数可以接受的参数类型:file对象(File),字符串路径(String),字节输出流(OutputStream)

(2)字符打印流:PrintWriter

构造函数可以接受的参数类型:file对象(File),字符串路径(String),字节输出流(OutputStream),字符输出流(Writer)

2、序列流:SequenceInputStream

将多个流给串联起来,以第一个流的开始为开始,以最后一个流的结尾为结尾。(多个源对应一个目的地)。常用语将多个流文件合并。

例子:

(1)创建一个集合,将流对象加入集合;

(2)创建枚举对象,将集合中的元素加入;

(3)创建Sequence对象,将流合并。

(4)创建一个输出流对象,将合并后的流输出。

public static void merge() throws IOException
{
ArrayList<FileInputStream> al=new ArrayList<FileInputStream>();

for(int x=1;x<22;x++)
{
al.add(new FileInputStream(""+x+".part"));
}
final Iterator<FileInputStream> it=al.iterator();

Enumeration<FileInputStream> en=new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream("xx.jpg");
byte[] buf=new byte[1024];
int len=0;
while((len=sis.read())!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}

3、操作对象:ObjectInputStream和ObjectOutputStream

存储在硬盘上可以长期存在------对象的序列化。

没有方法的接口-----标记接口

实现Serializable接口的类,会被标识,产生一个特定的UID,无法轻易更改。可以在类中自定义一个固定化的标识UID,这样,即使改变该类,那么下次依然可以被调用。

静态不能被序列化,堆里边的可以被序列化。

非静态成员如果不想被序列化,可以加个关键字 transient,保证其值在堆内存中存在,不在文本文件中存在。

4、管道流

PipedInputStream和PipedOutputStream

和文件流区别:不需要缓冲区间。

集合中涉及到IO流的是Properties,在IO流中涉及到多线程的就是管道流。

5、RandomAccessFile

该类不算是IO体系中子类,直接继承自Object。此类的实例支持对随机访问文件的读取和写入。但是它是IO包中成员,因为它具备读和写功能。

内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。

其实完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件。而且操作文件还可以指定操作模式。

而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖。

如果模式为r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常,如果模式为rw,则要操作的文件不存在,会自动创建,如果存在,则不会覆盖。

6、DataInputStream和DataOutputStream、ByteArrayInputStream和ByteArrayOutputStream、CharArrayReader和CharArrayWriter、StringReader和StringWriter

操作基本数据类型:DataInputStream和DataOutputStream

操作字节数组:ByteArrayInputStream和ByteArrayOutputStream

操作字符数组:CharArrayReader和CharArrayWriter

操作字符串:StringReader和StringWriter

你好—用GBK写4字节,用UTF-8:6字节 用DataOutputStream:8字节,readUTF()读8个字节。

ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组

ByteArrayOutputStream:在构造的时候,不用定义数据目的地,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。

因为这两个流对象都操作的数组,并没有使用系统资源,所以,不用进行close关闭。

ByteArrayInputStream bis=newByteArrayInputStream(“fasdas”.getBytes());

ByteArrayOutputStream bos=newByteArrayOutputStream(); 

int by=0;

while((by=bis.read())!=-1)

{

bos.write(by);

}

System.out.println(bos.size());

System.out.println(bos.toString());

用流的思想操作数组。

7、转换流的字符编码

字符流的出现是为了方便操作字符。更重要的时加入了编码转换,通过子类转换流来完成:InputStreamReader和OutputStreamWriter。

在两个对象进行构造的时候可以加入字符集。printStream和printWriter也可以加入编码表。

常见的编码表:ASCII:美国标准信息交换码。用一个字节的7位可以表示。

ISO8859-1:拉丁码表。欧洲码表。用一个字节的8位表示。

GB2312:中国的中文编码表。

GBK:中国的中文编码表升级。

Unicode:国际标准码。融合了多种文字。所有文字都用两个字节来表示,java语言使用的就是Unicode。

UTF-8:最多用3个字节来表示一个字符。

注:

编码:字符串变成字节数组

String->byte[]:str.getBytes(charsetName)  ->GBK编码表

解码:字节数组变成字符串

byte[]->String:new String(bytes[],charsetName);

GBK和UTF-8都识别中文,GBK以110开头。

服务器使用的是ISO8859-1。

UTF-8有自己的特征码。


 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
public static String loadAFileToStringDE1(File f) throws IOException { long beginTime = System.currentTimeMillis(); InputStream is = null; String ret = null; try { is = new BufferedInputStream( new FileInputStream(f) ); long contentLength = f.length(); ByteArrayOutputStream outstream = new ByteArrayOutputStream( contentLength > 0 ? (int) contentLength : 1024); byte[] buffer = new byte[4096]; int len; while ((len = is.read(buffer)) > 0) { outstream.write(buffer, 0, len); } outstream.close(); ret = outstream.toString(); //byte[] ba = outstream.toByteArray(); //ret = new String(ba); } finally { if(is!=null) {try{is.close();} catch(Exception e){} } } long endTime = System.currentTimeMillis(); System.out.println("方法1用时"+ (endTime-beginTime) + "ms"); return ret; } public static String loadAFileToStringDE2(File f) throws IOException { long beginTime = System.currentTimeMillis(); InputStream is = null; String ret = null; try { is = new FileInputStream(f) ; long contentLength = f.length(); byte[] ba = new byte[(int)contentLength]; is.read(ba); ret = new String(ba); } finally { if(is!=null) {try{is.close();} catch(Exception e){} } } long endTime = System.currentTimeMillis(); System.out.println("方法2用时"+ (endTime-beginTime) + "ms"); return ret; } public static String loadAFileToStringDE3(File f) throws IOException { long beginTime = System.currentTimeMillis(); BufferedReader br = null; String ret = null; try { br = new BufferedReader(new FileReader(f)); String line = null; StringBuffer sb = new StringBuffer((int)f.length()); while( (line = br.readLine() ) != null ) { sb.append(line).append(LINE_BREAK); } ret = sb.toString(); } finally { if(br!=null) {try{br.close();} catch(Exception e){} } } long endTime = System.currentTimeMillis(); System.out.println("方法3用时"+ (endTime-beginTime) + "ms"); return ret; } 3个方法去读取一个大于50M的文件,当不设置jvm参数时都OutofMemery,当设置-Xmx128M时。只有方法3 可以通过,设置到-Xmx256M时也只有方法3可以通过,干脆设置512M,都可以了,运行时间如果正常的话一般都在4~5S
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值