#1 Stream

Stream(스트림)은 데이터를 읽고 기록 하기 위한 중간 매개체입니다.

프로그래머가 사용할 코드를 만들 때, 장치와 관련된 스트림을 생성해서 쓰기만 하면됩니다. 간단하네요이해하기가 쉽네요^^.

입출력 계열의 스트림은 read와 write 메서드를 포함하고 있습니다.
   read계열의 메서드를 사용하면 데이터를 읽어들이고,
   write계열의 메서드를 사용하면 데이터를 기록(출력)합니다.

                            read() 메서드                            write() 메서드
    바이트 단위
int read() 
int read(byte cbuf[]) 
int read(byte cbuf[], int offset, int length)
   바이트 단위 
int write(int c) 
int write(byte cbuf[]) 
int write(byte cbuf[], int offset, int length)
    문자 단위
int read() 
int read(char cbuf[]) 
int read(char cbuf[], int offset, int length)
   문자 단위
int write(int c) 
int write(char cbuf[]) 
int write(char int offset, int length)


자바의 스트림은 입력 스트림과 출력 스트림으로 분리해서 생각해야하고, 바이트 스트림과 문자 스트림으로 나눌 수 있습니다. (실제는 아래보다 더 많습니다.)
(모든 스트림은 바이트 단위로 핸들 합니다.  문자(8바이트), 텍스트, 사진, zip, jar..모두 다.. 그런데, 사용할 수 있는 건 스트림에서 알아서 다 처리해주기 때문입니다.)

바이트 스트림 구성도
: InputStream, Outputstream 단어가 붙어있다면 바이트 스트림입니다.

문자 스트림 구성도
: Reader, Writer 단어가 붙어있다면 문자 스트림입니다.


▨ 예를 들면,
FileInputStream fis = new FileInputStream(파일); 
fis.read() 를 이용해서 데이터 읽기 
FileOutputStream fos = new FileOutputStream(파일); 
fos.write() 를 이용해서 데이터 쓰기







#2 System.in
package java.lang;                         //java.lang 패키지 안에 스태틱으로 선언 되있으므로, 그냥 가따 쓰기만 하면 됩니다.
public class System{ 
    public static PrintStream out; 
    public static InputStream in; 
    public static PrintStream err;  
}


[참고]
public static void main(String[] args) throws IOException{      //입력을 할땐 IOException 예외처리가 필요 하다
                                                                                        //얼마전.. 코딩할때 try, catch로 했었는데.. 더편한방법이..
   System.out.print("엔터를 누르세요");
   int i = System.in.read();                      //스트림 read를 사용하여 읽는다.
   System.out.println(i);                         //13 : '\r'  이 출력
   i = System.in.read();
   System.out.println(i);                         //10 : '\n'  이 출력
}









#3 File 클래스
: 다른 언어에서는 File 변수를 하나 만들어서 거기서 입출력까지 다했었던거같은데.. JAVA에서는 File클래스와 입출력 스트림이 따로 놀아야 됩니다.
import java.io.*;
import java.net.*;
import java.util.*;
public class FileMain {
   public static void main(String[] args) throws MalformedURLException{
      File f = new File("FileMain.java");
      PrintStream out = System.out;  //스트림을 따로만든다.
      out.println("isFile(): " + f.isFile());           //파일? 
      out.println("isDirectory(): " + f.isDirectory()); 
      out.println("isHidden(): " + f.isHidden()); //숨김파일?
      out.println("lastModified(): " + f.lastModified()); 
      out.println("canRead(): " + f.canRead()); //읽기 속성?
      out.println("canWrite(): " + f.canWrite());  //쓰기 속성?
      out.println("getPath(): " + f.getPath());     //상대 경로
      out.println("getAbsolutePath(): "+ f.getAbsolutePath()); //절대 경로
      out.println("getName(): " + f.getName()); //파일이름
      out.println("toURL(): " + f.toURL());  //URL형식의 경로
      out.println("exists(): " + f.exists()); //파일 존재여부 
      out.println("length(): " + f.length()); //파일 길이
 
      File[] fs = f.listFiles();          //디렉토리 목록가져오기
      for(int i=0; i<fs.length; i++){
         System.out.println(fs[i].getName());
      }
   } 
}







--------------------출력화면
isFile(): true
isDirectory(): false
isHidden(): false
lastModified(): 1087998966206
canRead(): true
canWrite(): true
getPath(): FileMain.java
getAbsolutePath(): C:\javasrc\chap09\FileMain.java

getName(): FileMain.java
toURL(): file:/C:/javasrc/chap09/FileMain.java
exists(): true
length(): 1253

bootfont.bin
CONFIG.SYS
Documents and Settings
...
...

                      생성                          삭제                     이름변경 
File f = new File("디렉토리명"); 
if(!f.exist()){ 
   f.mkdir(); 
}
File f = new File("파일명"); 
if(f.exist()){
   f.delete(); 
}
File f = new File("원본파일명"); 
File t = new File("변경할파일명"); 
if(f.exists()){
   f.renameTo(t); 
}


#3-1 File 스트림
: FileInputStream, FileOutputStream, FileReader, FileWriter
 위에 #1에서 바이트 단위, 문자단위로 write, read 메서드가 어떻게 생겼는지 봤습니다. 사용해보기로 하죠.
public class FileStreamMain3{ 
   public static void main(String[] args) throws IOException{
      File f = new File("a.dat");
      if(f.exists()){
         FileOutputStream fos = new FileOutputStream("a.dat", true);       //덮어쓰기false, 이어쓰기:true
         byte[] b = new byte[]{72, 101, 108, 108, 111};
         fos.write(b); 
         fos.write(101); 
         fos.close(); 
      }
   }
}
public class FileStreamMain6{
   public static void main(String[] args) throws IOException{
      File f = new File("FileStreamMain6.java");
      int fileSize = (int)f.length();
      System.out.println("size :" + fileSize);
      byte[] b = new byte[fileSize];
      FileInputStream fis = new FileInputStream("FileStreamMain6.java");
      int pos = 0, size = 10, temp; 
      //10byte씩 읽기
      while( (size=fis.read(b, pos, size)) > 0 ){
         pos += size;
         temp = b.length - pos;
         if(temp < 10)
            size = temp;  
      }
      fis.close();
      System.out.println("read size:" + pos);
      FileOutputStream fos = new FileOutputStream("test.txt");                //한번에 파일에 쓰기
      fos.write(b);
      fos.close();
   }
}
//처음 size와 다 읽었을 때 size가 같으면 정확히 쓴 것
public class FileWriterMain2{
   public static void main(String[] args) throws IOException{
      char[] content = new char[]{72, 101, 108, 108, 111};
      String str = new String("Hello World!");
      FileWriter fos = new FileWriter("writer2.dat");
      fos.write(content); 
      fos.write(str); 

      fos.close();
   }
}
public class FileReaderMain{
   public static void main(String[] args) throws IOException{
      FileReader fr = new FileReader("writer.dat");
      int i;
      while( (i=fr.read()) != -1 ){
         System.out.print((char)i);
      }
      fr.close();
   }
}
: 파일 복사
public class BufferedFileCopy {
//ex) java BufferedFileCopy s.exe t.exe
   public static void main(String[] args) throws IOException{
      int i, len=0;
      FileInputStream fis = new FileInputStream(args[0]);               //아래 Buffered스트림을 안써도되지만, 그럼 더느리다.
      FileOutputStream fos = new FileOutputStream(args[1]);
      BufferedInputStream bis = new BufferedInputStream(fis);           //Buffered스트림을 사용한 복사가 빨르다.
      BufferedOutputStream bos = new BufferedOutputStream(fos);    //Buffered스트림 없이도 복사가 가능하다
      long psecond = System.currentTimeMillis();
      while((i=bis.read()) != -1) {
         bos.write(i);
         len++;
      }
      bis.close();
      bos.close();
      psecond = System.currentTimeMillis() - psecond;
      System.out.println(len + " bytes " + psecond +" miliseconds"); 
   }
}


#3-2 RandomAccessFile 클래스
: 임의 접근, 파일의 아무 곳에서 부터 읽고 쓸수 있다
   RandomAccessFile rf = new RandomAccessFile("파일명", "모드");    //모드: r, rw..
   rf.seek(10);  

//offset이 10인 위치로 이동해서 수정하면된다. 







#4 Memory 스트림, 2차 스트림
스트림을 한번 쭉.. 보니.. 사용법이 다 같네요. 사용하기도 쉽고.. 역시 자바가 프로그래밍을 하기 쉬운 언어인거 같긴하네요ㅎ
             Memory 스트림들 
ByteArrayInputStream 
ByteArrayOutputStream 
CharArrayInputStream 
CharArrayOutputStream 
StringReader 
StringWriter

          대표적인 1차 스트림들 
InputStream, OutputStream 
FileInputStream, FileOutputStream 
FileReader, FileWriter 
ByteArrayInputStream, ByteArrayOutputStream 
CharArrayReader, CharArrayWriter 
StringReader, StringWriter
          대표적인 2차 스트림들 
InputStreamReader, OutputStreamWriter 
DataInputStream, DataOutputStream 
BufferedInputStream, BufferedOutputStream 
BufferedReader, BufferedWriter 
ObjectInputStream, ObjectOutputStream
사용법은 위에서 설명한 대로와 모두 같아서, 특별히 사용법은 안써도 될꺼 같네요.
스트림들을 구분해서 설명해보겠습니다.

Memory 스트림에는 바이트배열과 문자배열(문자열)이 있습니다. 이 스트림을 쓰면, 한정된 배열의 크기를 정하지 않고도 동적으로 메모리를 할당해서 사용할수 있으므로 유용합니다. 출력스트림에서 기록된 모든 데이터를 배열로 얻을 수 있다는 장점이 있습니다. String은 문자열이 진화한 것이죠.
사용:
byte[] arr = {'j', 'a', 'b', 'o', 'o', 'k'}; 
byte[] result = out.toByteArray();  // 모든 데이터를 배열로 받아내기 (타 스트림 : .toCharArray() / .toString() .getBuffer())
System.out.print((char)result[3]); // read할때 int형으로 저장되므로 char로 변형

▨ 1차 스트림은 목표지점까지 직접 연결된다는 것입니다. 즉, 한번만 가공된다는 겁니다.

2차 스트림은 1차 스트림에서 원하는 대로 2차스트림으로 한번더 가공한다는 것입니다. 예를 들면, FileInputStream을 버퍼링이 지원되는 BufferedInputStream로 변형하면 데이터 읽고 쓰는 속도가 더 빠릅니다.
사용:
1. FileInputStream fis = new FileInputStream("파일명");               
   InputStreamReader isr = new InputStreamReader(fis);              //파일에서 읽어올때, 문자로 가져온다.  
2. InputStreamReader isr = new InputStreamReader(System.in);   //System.in은 InputStream이다. 
   System.out.println("종료하기 위해서는 '끝'을 입력하시오"); 
   System.out.println("출력할 데이터를 입력하시오? "); 
   while((i = isr.read()) != '끝') {                                         //핸들을 바이트에서 문자로 바꿔서 인식해 한글을 구분한다.
      System.out.print((char)i); 
   }
3. FileOutputStream fos = new FileOutputStream("data.dat");
   DataOutputStream dos = new DataOutputStream(fos);
   dos.writeFloat(3.14f);                                                          //4바이트를 float형식으로 쓰기
   FileInputStream fis = new FileInputStream("data.dat");
   DataInputStream dis = new DataInputStream(fis); 
   float f = dis.readFloat();                                                       
3. FileOutputStream fos = new FileOutputStream("serial.dat");     //직렬화(Serialization) 
   ObjectOutputStream oos = new ObjectOutputStream(fos);
   SampleData s1 = new SampleData("홍길동", 1004); 
   oos.writeObject(s1);                                                           //객체의 멤버변수값들을 직렬화해서 저장한다.
   FileInputStream fis = new FileInputStream("serial.dat");           //역직렬화(Deserialization) 
   ObjectInputStream ois = new ObjectInputStream(fis);
   SampleData sd1 = (SampleData)ois.readObject();                 //저장된 멤버변수값들을 역직렬화해서 가져온다.
   System.out.println(sd1 + ":" + sd1.getSampleData()); 







ps. 스트림.. 다른 센션보다 좀더 볼게 많았던거 같은데, 결국 스트림이름만 다르고, 사용방법은 모두 같네요.