package railo.commons.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.util.LinkedList;
import java.util.zip.ZipFile;
import javax.mail.Transport;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.commons.net.URLEncoder;
import railo.runtime.exp.PageException;
import com.lowagie.text.Document;
/**
* I/O Util
*/
public final class IOUtil {
/**
* copy a inputstream to a outputstream
* @param in
* @param out
* @param closeIS
* @param closeOS
* @throws IOException
*/
public static final void copy(InputStream in, OutputStream out, boolean closeIS, boolean closeOS) throws IOException {
try {
copy(in,out,0xffff);
}
finally {
if(closeIS)closeEL(in);
if(closeOS)closeEL(out);
}
}
/**
* copy a inputstream to a outputstream
* @param in
* @param out
* @param closeIS
* @param closeOS
* @throws IOException
*/
public static final void merge(InputStream in1, InputStream in2, OutputStream out, boolean closeIS1, boolean closeIS2, boolean closeOS) throws IOException {
try {
merge(in1,in2,out,0xffff);
}
finally {
if(closeIS1)closeEL(in1);
if(closeIS2)closeEL(in2);
if(closeOS)closeEL(out);
}
}
/**
* copy a inputstream to a outputstream
* @param in
* @param out
* @param closeIS
* @param closeOS
* @throws IOException
*/
public static final void copy(OutputStream out, InputStream in,boolean closeIS, boolean closeOS) throws IOException {
copy(in,out,closeIS,closeOS);
}
/**
* copy a input resource to a output resource
* @param in
* @param out
* @throws IOException
*/
public static void copy(Resource in, Resource out) throws IOException {
in.copyTo(out, false);
}
public static void merge(Resource in1, Resource in2, Resource out) throws IOException {
InputStream is1=null;
InputStream is2=null;
OutputStream os=null;
try {
is1=toBufferedInputStream(in1.getInputStream());
is2=toBufferedInputStream(in2.getInputStream());
os=toBufferedOutputStream(out.getOutputStream());
}
catch(IOException ioe) {
IOUtil.closeEL(is1);
IOUtil.closeEL(is2);
IOUtil.closeEL(os);
throw ioe;
}
merge(is1,is2,os,true,true,true);
}
/**
* copy a input resource to a output resource
* @param in
* @param out
* @throws IOException
*/
public static void copy(InputStream is, Resource out, boolean closeIS) throws IOException {
OutputStream os=null;
try {
os=toBufferedOutputStream(out.getOutputStream());
}
catch(IOException ioe) {
IOUtil.closeEL(os);
throw ioe;
}
copy(is,os,closeIS,true);
}
/**
* copy a input resource to a output resource
* @param in
* @param out
* @throws IOException
*/
public static void copy(Resource in, OutputStream os, boolean closeOS) throws IOException {
InputStream is=null;
try {
is=toBufferedInputStream(in.getInputStream());
}
catch(IOException ioe) {
IOUtil.closeEL(is);
throw ioe;
}
copy(is,os,true,closeOS);
}
public static final void copy(InputStream in, OutputStream out, int offset, int length) throws IOException {
copy(in, out, offset, length,0xffff);
}
public static final void copy(InputStream in, OutputStream out, long offset, long length) throws IOException {
int len;
byte[] buffer;
int block=0xffff;
// first offset to start
if(offset>0) {
long skipped=0;
try{
skipped = in.skip(offset);
}
catch(Throwable t){}
if(skipped<=0) {
while(true) {
if(block>offset)block=(int)offset;
buffer = new byte[block];
len = in.read(buffer);
if(len==-1) throw new IOException("reading offset is bigger than input itself");
//dnos.write(buffer, 0, len);
offset-=len;
if(offset<=0) break;
}
}
}
// write part
if(length<0) {
copy(in, out,block);
return;
}
while(true) {
if(block>length)block=(int) length;
buffer = new byte[block];
len = in.read(buffer);
if(len==-1) break;
out.write(buffer, 0, len);
length-=len;
if(length<=0) break;
}
}
public static final void copy(InputStream in, OutputStream out, int offset, int length, int blockSize) throws IOException {
int len;
byte[] buffer;
int block;//0xffff;
// first offset to start
if(offset>0) {
long skipped=0;
try{
skipped = in.skip(offset);
}
catch(Throwable t){}
if(skipped<=0) {
block = blockSize;//0xffff;
while(true) {
if(block>offset)block=offset;
buffer = new byte[block];
len = in.read(buffer);
if(len==-1) throw new IOException("reading offset is bigger than input itself");
//dnos.write(buffer, 0, len);
offset-=len;
if(offset<=0) break;
}
}
}
// write part
if(length<0) {
copy(in, out,blockSize);
return;
}
block = blockSize;//0xffff;
while(true) {
if(block>length)block=length;
buffer = new byte[block];
len = in.read(buffer);
if(len==-1) break;
out.write(buffer, 0, len);
length-=len;
if(length<=0) break;
}
}
/**
* copy a inputstream to a outputstream
* @param in
* @param out
* @param blockSize
* @throws IOException
*/
private static final void copy(InputStream in, OutputStream out, int blockSize) throws IOException {
byte[] buffer = new byte[blockSize];
int len;
while((len = in.read(buffer)) !=-1) {
out.write(buffer, 0, len);
}
}
private static final void merge(InputStream in1, InputStream in2, OutputStream out, int blockSize) throws IOException {
copy(in1, out,blockSize);
copy(in2, out,blockSize);
}
/**
* copy a reader to a writer
* @param r
* @param w
* @throws IOException
*/
private static final void copy(Reader r, Writer w) throws IOException {
copy(r,w,0xffff);
}
/**
* copy a reader to a writer
* @param reader
* @param writer
* @param closeReader
* @param closeWriter
* @throws IOException
*/
public static final void copy(Reader reader, Writer writer, boolean closeReader, boolean closeWriter) throws IOException {
try {
copy(reader,writer,0xffff);
}
finally {
if(closeReader)closeEL(reader);
if(closeWriter)closeEL(writer);
}
}
/**
* copy a reader to a writer
* @param r
* @param w
* @param blockSize
* @throws IOException
*/
private static final void copy(Reader r, Writer w, int blockSize) throws IOException {
char[] buffer = new char[blockSize];
int len;
while((len = r.read(buffer)) !=-1)
w.write(buffer, 0, len);
}
/**
* copy content of in file to out File
* @param in input
* @param out output
* @throws IOException
*/
public void copy(File in,File out) throws IOException {
InputStream is=null;
OutputStream os=null;
try {
is = new BufferedFileInputStream(in);
os = new BufferedFileOutputStream(out);
}
catch (IOException ioe) {
closeEL(is,os);
throw ioe;
}
copy(is,os,true,true);
}
/**
* close inputstream without a Exception
* @param is
* @param os
*/
public static void closeEL(InputStream is, OutputStream os) {
closeEL(is);
closeEL(os);
}
/**
* close inputstream without a Exception
* @param is
*/
public static void closeEL(InputStream is) {
try {
if(is!=null)is.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable t) {}
}
public static void closeEL(ZipFile zip) {
try {
if(zip!=null)zip.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable t) {}
}
/**
* close outputstream without a Exception
* @param os
*/
public static void closeEL(OutputStream os) {
try {
if(os!=null)os.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable e) {}
}
public static void closeEL(ResultSet rs) {
try {
if(rs!=null)rs.close();
}
catch (Throwable e) {}
}
/**
* close Reader without a Exception
* @param r
*/
public static void closeEL(Reader r) {
try {
if(r!=null)r.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable e) {}
}
/**
* close Closeable without a Exception
* @param r
*/
public static void closeEL(Closeable c ) {
try {
if(c!=null)c.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable e) {}
}
/**
* close Writer without a Exception
* @param w
*/
public static void closeEL(Writer w) {
try {
if(w!=null)w.close();
}
//catch (AlwaysThrow at) {throw at;}
catch (Throwable e) {}
}
/**
* close Writer without a Exception
* @param w
*/
public static void closeEL(Transport t) {
try {
if(t!=null && t.isConnected())t.close();
}
catch (Throwable e) {}
}
public static void closeEL(Document doc) {
try {
if(doc!=null)doc.close();
}
catch (Throwable e) {}
}
/**
* call close method from any Object with a close method.
* @param obj
*/
public static void closeEL(Object obj) {
if(obj instanceof InputStream) IOUtil.closeEL((InputStream)obj);
else if(obj instanceof OutputStream) IOUtil.closeEL((OutputStream)obj);
else if(obj instanceof Writer) IOUtil.closeEL((Writer)obj);
else if(obj instanceof Reader) IOUtil.closeEL((Reader)obj);
else if(obj instanceof Closeable) IOUtil.closeEL((Closeable)obj);
else if(obj instanceof ZipFile) IOUtil.closeEL((ZipFile)obj);
else if(obj instanceof ResultSet) IOUtil.closeEL((ResultSet)obj);
else {
try {
Method method = obj.getClass().getMethod("close",new Class[0]);
method.invoke(obj,new Object[0]);
}
catch (Throwable e) {}
}
}
/**
* @deprecated use instead <code>{@link #getReader(Resource, Charset)}</code>
* @param res
* @param charset
* @return
* @throws IOException
*/
public static Reader getReader(Resource res, String charset) throws IOException {
return getReader(res, CharsetUtil.toCharset(charset));
}
public static Reader getReader(Resource res, Charset charset) throws IOException {
/*
00 00 FE FF UTF-32, big-endian
FF FE 00 00 UTF-32, little-endian
*/
InputStream is=null;
try {
is = res.getInputStream();
boolean markSupported=is.markSupported();
if(markSupported) is.mark(4);
int first = is.read();
int second = is.read();
// FE FF UTF-16, big-endian
if (first == 0xFE && second == 0xFF) {
return _getReader(is, CharsetUtil.UTF16BE);
}
// FF FE UTF-16, little-endian
if (first == 0xFF && second == 0xFE) {
return _getReader(is, CharsetUtil.UTF16LE);
}
int third=is.read();
// EF BB BF UTF-8
if (first == 0xEF && second == 0xBB && third == 0xBF) {
//is.reset();
return _getReader(is,CharsetUtil.UTF8);
}
/*
int forth=is.read();
// 00 00 FE FF UTF-32, big-endian
if (first == 0x00 && second == 0x00 && third == 0xFE && forth == 0xFF) {
is.reset();
return _getReader(is, "utf-32");
}
// FF FE 00 00 UTF-32, little-endian
if (first == 0xFF && second == 0xFE && third == 0x00 && forth == 0x00) {
is.reset();
return _getReader(is, "utf-32");
}*/
if(markSupported) {
is.reset();
return _getReader(is,charset);
}
}
catch(IOException ioe) {
IOUtil.closeEL(is);
throw ioe;
}
// when mark not supported return new reader
closeEL(is);
is=null;
try {
is=res.getInputStream();
}
catch(IOException ioe) {
closeEL(is);
throw ioe;
}
return _getReader(is, charset);
}
public static Reader getReader(InputStream is, Charset charset) throws IOException {
boolean markSupported=is.markSupported();
if(!markSupported) return _getReader(is, charset);
if(markSupported) is.mark(4);
int first = is.read();
int second = is.read();
// FE FF UTF-16, big-endian
if (first == 0xFE && second == 0xFF) {
//is.reset();
return _getReader(is, CharsetUtil.UTF16BE);
}
// FF FE UTF-16, little-endian
if (first == 0xFF && second == 0xFE) {
return _getReader(is, CharsetUtil.UTF16LE);
}
int third=is.read();
// EF BB BF UTF-8
if (first == 0xEF && second == 0xBB && third == 0xBF) {
return _getReader(is, CharsetUtil.UTF8);
}
is.reset();
return _getReader(is,charset);
}
/**
* @deprecated use instead <code>{@link #getReader(InputStream, Charset)}</code>
* @param is
* @param charset
* @return
* @throws IOException
*/
public static Reader getReader(InputStream is, String charset) throws IOException {
return getReader(is, CharsetUtil.toCharset(charset));
}
/**
* returns a Reader for the given InputStream
* @param is
* @param charset
* @return Reader
* @throws IOException
*/
private static Reader _getReader(InputStream is, Charset charset) throws IOException {
if(charset==null) charset=SystemUtil.getCharset();
return new BufferedReader(new InputStreamReader(is,charset));
}
/**
* @deprecated use instead <code>{@link #toString(InputStream, Charset)}</code>
* @param is
* @param charset
* @return
* @throws IOException
*/
public static String toString(InputStream is, String charset) throws IOException {
return toString(is,CharsetUtil.toCharset(charset));
}
/**
* reads string data from a InputStream
* @param is
* @param charset
* @return string from inputstream
* @throws IOException
*/
public static String toString(InputStream is, Charset charset) throws IOException {
return toString(getReader(is,charset));
}
/**
* @deprecated use instead <code>{@link #toString(byte[], Charset)}</code>
* @param barr
* @param charset
* @return
* @throws IOException
*/
public static String toString(byte[] barr, String charset) throws IOException {
return toString(barr,CharsetUtil.toCharset(charset));
}
public static String toString(byte[] barr, Charset charset) throws IOException {
return toString(getReader(new ByteArrayInputStream(barr),charset));
}
/**
* reads String data from a Reader
* @param reader
* @return readed string
* @throws IOException
*/
public static String toString(Reader reader) throws IOException {
StringWriter sw=new StringWriter(512);
copy(toBufferedReader(reader),sw);
sw.close();
return sw.toString();
}
/**
* reads String data from a Reader
* @param reader
* @return readed string
* @throws IOException
*/
public static String toString(Reader reader,boolean buffered) throws IOException {
StringWriter sw=new StringWriter(512);
if(buffered)copy(toBufferedReader(reader),sw);
else copy(reader,sw);
sw.close();
return sw.toString();
}
/**
* @deprecated use instead <code>{@link #toString(Resource, Charset)}</code>
* @param file
* @param charset
* @return
* @throws IOException
*/
public static String toString(Resource file, String charset) throws IOException {
return toString(file, CharsetUtil.toCharset(charset));
}
/**
* reads String data from File
* @param file
* @param charset
* @return readed string
* @throws IOException
*/
public static String toString(Resource file, Charset charset) throws IOException {
Reader r = null;
try {
r = getReader(file,charset);
String str = toString(r);
return str;
}
finally {
closeEL(r);
}
}
/**
* @param reader Reader to get content from it
* @return returns the content of the file as String Array (Line by Line)
* @throws IOException
*/
public static String[] toStringArray(Reader reader) throws IOException {
if(reader==null)return new String[0];
BufferedReader br = new BufferedReader(reader);
LinkedList<String> list=new LinkedList<String>();
String line;
while((line=br.readLine())!=null) {
list.add(line);
}
br.close();
String[] content=new String[list.size()];
int count=0;
while(!list.isEmpty()) {
content[count++]=list.removeFirst();
}
return content;
}
/**
* @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code>
* writes a String to a object
* @param file
* @param string String to write to file
* @param charset
* @param append append to cuuretn data or overwrite existing data
* @throws IOException
*/
public static void write(File file, String string, String strCharset, boolean append) throws IOException {
Charset charset;
if(StringUtil.isEmpty(strCharset)) {
charset=SystemUtil.getCharset();
}
else charset=CharsetUtil.toCharset(strCharset);
OutputStreamWriter writer=null;
try {
writer=new OutputStreamWriter(new BufferedFileOutputStream(file,append),charset);
writer.write(string);
}
finally {
closeEL(writer);
}
}
/**
* @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code>
* @param res
* @param string
* @param charset
* @param append
* @throws IOException
*/
public static void write(Resource res, String string, String charset, boolean append) throws IOException {
write(res, string, CharsetUtil.toCharset(charset), append);
}
public static void write(Resource res, String string, Charset charset, boolean append) throws IOException {
if(charset==null) {
charset=SystemUtil.getCharset();
}
Writer writer=null;
try {
writer=getWriter(res, charset,append);
writer.write(string);
}
finally {
closeEL(writer);
}
}
public static void write(Resource res, byte[] barr) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(barr);
OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream());
IOUtil.copy(bais, os, true, true);
}
public static void write(Resource res, byte[] barr, boolean append) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(barr);
OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream(append));
IOUtil.copy(bais, os, true, true);
}
/**
* @deprecated use instead <code>{@link #toBytes(Resource)}</code>
* @param file
* @return returns the Content of the file as byte array
* @throws IOException
*/
public static byte[] toBytes(File file) throws IOException {
BufferedFileInputStream bfis = null;
try {
bfis = new BufferedFileInputStream(file);
byte[] barr = toBytes(bfis);
return barr;
}
finally {
closeEL(bfis);
}
}
/**
* @param res
* @return returns the Content of the file as byte array
* @throws IOException
*/
public static byte[] toBytes(Resource res) throws IOException {
BufferedInputStream bfis = null;
try {
bfis = toBufferedInputStream(res.getInputStream());
byte[] barr = toBytes(bfis);
return barr;
}
finally {
closeEL(bfis);
}
}
public static BufferedInputStream toBufferedInputStream(InputStream is) {
if(is instanceof BufferedInputStream) return (BufferedInputStream) is;
return new BufferedInputStream(is);
}
public static BufferedOutputStream toBufferedOutputStream(OutputStream os) {
if(os instanceof BufferedOutputStream) return (BufferedOutputStream) os;
return new BufferedOutputStream(os);
}
public static BufferedReader toBufferedReader(Reader r) {
if(r instanceof BufferedReader) return (BufferedReader) r;
return new BufferedReader(r);
}
/**
* @deprecated use instead <code>{@link #getBufferedReader(Resource, Charset)}</code>
* @param res
* @param charset
* @return
* @throws IOException
*/
public static BufferedReader getBufferedReader(Resource res,String charset) throws IOException {
return getBufferedReader(res,CharsetUtil.toCharset(charset));
}
public static BufferedReader getBufferedReader(Resource res,Charset charset) throws IOException {
return toBufferedReader(getReader(res, charset));
}
public static BufferedWriter toBufferedWriter(Writer w) {
if(w instanceof BufferedWriter) return (BufferedWriter) w;
return new BufferedWriter(w);
}
/**
* @param is
* @return returns the Content of the file as byte array
* @throws IOException
*/
public static byte[] toBytes(InputStream is) throws IOException {
return toBytes(is,false);
}
public static byte[] toBytes(InputStream is, boolean closeStream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(is,baos,closeStream,true);
return baos.toByteArray();
}
public static byte[] toBytesMax(InputStream is, int max) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(is,baos,0,max);
return baos.toByteArray();
}
/**
* flush OutputStream without a Exception
* @param os
*/
public static void flushEL(OutputStream os) {
try {
if(os!=null)os.flush();
} catch (Exception e) {}
}
/**
* flush OutputStream without a Exception
* @param os
*/
public static void flushEL(Writer w) {
try {
if(w!=null)w.flush();
} catch (Exception e) {}
}
/**
* check if given encoding is ok
* @param encoding
* @throws PageException
*/
public static void checkEncoding(String encoding) throws IOException {
try {
URLEncoder.encode("", encoding);
} catch (UnsupportedEncodingException e) {
throw new IOException("invalid encoding ["+encoding+"]");
}
}
/**
* return the mime type of a file, dont check extension
* @param barr
* @param defaultValue
* @return mime type of the file
*/
public static String getMimeType(InputStream is, String defaultValue) {
try {
return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
} catch (IOException e) {
return defaultValue;
}
/*try {
return URLConnection.guessContentTypeFromStream(is);
} catch (Throwable t) {
return defaultValue;
}*/
/*try {
return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
} catch (IOException e) {
return defaultValue;
}*/
}
/**
* return the mime type of a file, dont check extension
* @param barr
* @return mime type of the file
* @throws IOException
*/
public static String getMimeType(byte[] barr, String defaultValue) {
//String mt = getMimeType(new ByteArrayInputStream(barr), null);
//if(!StringUtil.isEmpty(mt,true)) return mt;
PrintStream out = System.out;
try {
System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM));
MagicMatch match = Magic.getMagicMatch(barr);
return match.getMimeType();
}
catch (Throwable t) {
return defaultValue;
}
finally {
System.setOut(out);
}
}
/**
* @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code>
* @param res
* @param charset
* @return
* @throws IOException
*/
public static Writer getWriter(Resource res, String charset) throws IOException {
return getWriter(res, CharsetUtil.toCharset(charset));
}
public static Writer getWriter(Resource res, Charset charset) throws IOException {
OutputStream os=null;
try {
os=res.getOutputStream();
}
catch(IOException ioe) {
closeEL(os);
throw ioe;
}
return getWriter(os, charset);
}
/**
* @deprecated use instead <code>{@link #getWriter(Resource, Charset,boolean)}</code>
* @param res
* @param charset
* @param append
* @return
* @throws IOException
*/
public static Writer getWriter(Resource res, String charset, boolean append) throws IOException {
return getWriter(res, CharsetUtil.toCharset(charset), append);
}
public static Writer getWriter(Resource res, Charset charset, boolean append) throws IOException {
OutputStream os=null;
try {
os=res.getOutputStream(append);
}
catch(IOException ioe) {
closeEL(os);
throw ioe;
}
return getWriter(os, charset);
}
/**
* @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code>
* returns a Reader for the given File and charset (Automaticly check BOM Files)
* @param file
* @param charset
* @return Reader
* @throws IOException
*/
public static Writer getWriter(File file, String charset) throws IOException {
OutputStream os=null;
try {
os=new FileOutputStream(file);
}
catch(IOException ioe) {
closeEL(os);
throw ioe;
}
return getWriter(os, charset);
}
/**
* @deprecated use instead <code>{@link #getWriter(Resource, Charset, boolean)}</code>
* returns a Reader for the given File and charset (Automaticly check BOM Files)
* @param file
* @param charset
* @return Reader
* @throws IOException
*/
public static Writer getWriter(File file, String charset, boolean append) throws IOException {
OutputStream os=null;
try {
os=new FileOutputStream(file,append);
}
catch(IOException ioe) {
closeEL(os);
throw ioe;
}
return getWriter(os, charset);
}
/**
* @deprecated use instead <code>{@link #getWriter(OutputStream, Charset)}</code>
* @param os
* @param charset
* @return
* @throws IOException
*/
public static Writer getWriter(OutputStream os, String charset) throws IOException {
return getWriter(os, CharsetUtil.toCharset(charset));
}
/**
* returns a Reader for the given InputStream
* @param is
* @param charset
* @return Reader
* @throws IOException
*/
public static Writer getWriter(OutputStream os, Charset charset) throws IOException {
if(charset==null) charset=SystemUtil.getCharset();
return new BufferedWriter(new OutputStreamWriter(os,charset));
}
public static String read(Reader reader, int size) throws IOException {
return read(reader, new char[size]);
}
public static String read(Reader reader,char[] carr) throws IOException {
int rst = reader.read(carr);
if(rst==-1)return null;
return new String(carr,0,rst);
}
}