자바 입출력( java stream )

2011.12.08 16:53

가을의 곰을... 조회 수:6845

자바 입출력( java stream )

http://blog.naver.com/hkn10004/20122267759

[출처] http://blog.naver.com/hkn10004?Redirect=Log&logNo=20122267759

  • 1. 자바 입출력 구조

객체가 가지고 있는 데이터는 파일에서 읽어올 수도 있고 파일에 저장할 수도 있다. 또한 파일 뿐만 아니라, 프린터나 네트워크와 같은 외부 장치에 데이터를 출력할 수도 있다. 이러한 파일 입출력의 기본은 스트림( stream )이다. 스트림이란 바이트 단위의 데이터를 기본으로 한 순차적인 입력 또는 출력의 단방향 흐름이다.

< 자바 입출력 구조 >

자바 입출력

파일

기본 입출력

필터 입출력

문자 입출력

비순차 접근 파일

객체 입출력

파일 입출력

바이트 배열 입출력

파이프 입출력

연결형 입력

스트링 버퍼 입력

1. 자바 입출력 방식

자바 입출력 방식은 크게 바이너리 입출력, 문자 입출력, 기본 데이터형 입출력, 객체 입출력, 스트림 토큰화로 분류할 수 있다.

바이너리 입출력

바이너리 입출력( Binary I/O )은 가장 기본이 되는 저수준의 입출력이다. 기본적으로 바이트 단위로 입출력되기 때문에 바이트 입출력이라고 하며, 파일 입출력 역시 기본적으로 바이너리 입출력에 해당한다.바이너리 입출력 속도를 높이기 위해 버퍼 입출력 스트림을 이용할 수도 있다.

문자 입출력

바이너리 입출력을 통해서 문자를 입출력하려면 유니코드와 지역코드를 상호 변경해 줄 수 있는 컨버터가 필요하다. 이 컨버터를 포함한 클래스가 바로 Reader 및 Writer 계열의 클래스다. 바이너리 입출력도 버퍼 입출력을 가지고 있듯이 문자 입출력( Character I/O )도 버퍼 입출력( BufferedReader와 BufferedWriter )을 가지고 있다.

기본 데이터형 입출력

바이너리 입출력을 통해서 기본 데이터형인 byte, char, short, int, double, float, long 등의 데이터를 1:1로 대응하여 입출력하는 것이다. 기본 데이터형 입출력( Primitive I/O )은 자바 언어가 사용하는 데이터형을 그대로 바이너리로 대응시킨 것으로 데이터 자체를 저장하고 복원하는 데 사용한다. 마찬가지로 버퍼 입출력을 이용할 수 있다.

객체 입출력

객체 입출력( Object I/O )은 기본 데이터형 입출력과 달리 객체를 바이트 단위로 입출력하는 것이다. 자바 객체를 저장하기 위해서는 단순히 바이트나 문자로 입출력하는 것에 비해 복잡한 과정을 거친다. 이를 위해서 객체 직렬화( object serialization ) 기법을 이용한다. 직렬화란 객체를 바이트 단위로 나눠서 입출력이 가능하게 만드는 과정을 말한다.

스트림 토큰화

스트림 토큰화( StreamTokenizing )는 사용자가 지정한 규칙에 따라서 문자열을 읽어들여서 특정한 파싱을 가능하게 하며, 단어 단위로 데이터를 읽거나 콤마(,), 콜론(:), 세미콜론(;), 등호(=)와 같은 기호를 구분자로 해서 문자열을 읽어들이는 데 사용한다. StreamTokenizer 클래스는 문자열을 처리하는 클래스므로 문자 기반 입출력 클래스인 Reader 객체를 생성자의 인자값으로 해야 한다. 일반 데이터 입출력 클래스인 InputStream 객체를 이용하는 것은 권장하지 않는다.

< 입출력 스트림 관련 클래스 >

입출력 종류

클래스 파일

바이트 스트림

InputStream, OutputStream

파일 스트림

FileInputStream, FileOutputStream

바이트 배열 스트림

ByteArrayInputStream, ByteArrayOutputStream

데이터 스트림

DataInputStream, DataOutputStream

객체 스트림

ObjectInputStream, ObjectOutputStream

문자 스트림

Reader, Writer

파일 문자 스트림

FileReader, FileWriter

문자 배열 스트림

CharArrayReader, CharArrayWriter

문자열 스트림

StringBufferInputStream, StringBufferReader, StringBufferWriter

파이프 입출력

PipeInputStream, PipeOutputStream

PipeReader, PipeWriter

스트림 필터

FilterInputStream, FilterOutputStream

FilterReader, FilterWriter

버퍼 스트림

BufferedInputStream, BufferedOutputStream

BufferedReader, BufferedWriter

반환형 스트림

PushbackInputStream, PushbackReader

기타 스트림

SequenceInputStream

비순차 입출력

RandomAccessFile

스트림 토큰화

StreamTokenizer

입력 스트림과 출력 스트림

스트림이란 데이터를 바이트 형태로 입출력하는 흐름이라 할 수 있다. 스트림은 시작점( 소스, source )과 종료점( 싱크, sink )을 가지고 있으며, 흐르는 방향은 생성 시점에서 단일 방향으로 고정된다. 스트림은 상하수도 파이프와 유사한 개념으로, 상수도를 입력 스트림으로, 하수도를 출력 스트림으로 생각하면 쉽게 이해할 수 있다.

입력 스트림의 소스와 프로그램 내부에서 밖으로 나가는 출력 스트림의 싱크에는 다양한 형태가 존재할 수 있다. 입력 스트림의 소스나 출력 스트림의 싱크가 될 수 있는 예를 살펴보면 다음과 같다.

. 바이트 배열

. String 객체

. 파일

. 파이프( 운영체제 용어 )

. 다른 스트림

. 네트워크 접속

. 콘솔( 입력의 경우엔 키보드, 출력의 경우엔 화면 )

2. 파일

참고 : http://download.oracle.com/javase/6/docs/api/java/io/File.html

일반적으로 입출력은 파일을 통해서 이루어진다. 자바 언어에 있어서도 파일은 매우 중요한 개념이다. 하지만 자바 입출력 패키지의 File 클래스는 입출력과는 직접적인 관련이 없다.즉, File 객체를 통해서 입출력을 수행하지 못한다. 다만, File 객체는 파일 또는 디렉토리를 접근하는 매체로 사용된다. 따라서 실제로 입출력하려면 스트림이나 비순차 접근을 지원하는 RandonAccessFile 클래스를 이용해야 한다.

File 클래스는 파일 또는 디렉토리 정보를 생성하거나 삭제하는 기능만 제공한다. File 생성자는 String 객체인 문자열을 인자값으로 해서 File 객체를 생성한다. 생성된 File 객체는 파일면과 경로( 디렉토리 ) 정보를 가지고 있다. 경로에는 현재 디렉토리와 상관없이 지정하는 절대 경로와 현재 디렉토리에 따라 파일 위치가 변하는 상대 경로가 있다. 자바 언어는 멀티 플랫폼을 지원하기 때문에 디렉토리를 표시하는 형태는 운영체제에 따라 달라진다. 윈도우와 유닉스의 디렉토리 정보는 다음과 같다.

운영체제

절대 경로

상대 경로

윈도우

C:\directory\sub ( 지역 파일 )

\server\shared_directory( 네트워크 파일 )

.\ 현재 디렉토리

..\ 상위 디렉토리

유닉스

/usr/src

./ 현재 디렉토리

../ 상위 디렉토리

앞에서 말한 것처럼, File 객체의 메소드를 이용해서 파일을 입출력할 수는 없지만 스트림 객체를 생성할 때 인자값으로 이용할 수는 있다. 또한 파일이 현재 존재하는지 여부와 파일 속성( 읽기 전용, 쓰기 전용, 읽기 쓰기 가능 )을 알 수 있다. 그리고 현재 디렉토리에 있는 파일 목록을 얻는 메소드도 제공한다.

File 객체는 final로 지정되어 있어 한 번 생성하면 변경할 수 없다. 따라서 File 객체의 참조 변수에 다른 File 객체를 저장할 수 없다. 다음 몇 가지 사항은 파일과 관련된 오류를 줄일 수 있는 방법이다.

. FileInputStream 객체를 생성하기 전에 인자값인 File 객체를 통해서 파일이 실제로 존재하는 것인지 확인한다.

. File 객체의 isFile() 메소드는 파일이 디렉토리인지 파일이지 확인하는 메소드다.

. 파일을 읽기 전에 canRead() 메소드를 이용하면 파일이 읽기 속성을 가지고 있는지 확인할 수 있다.

. 파일을 쓰기 전에 canWrite() 메소드를 이용하면 파일이 쓰기 속성을 가지고 있는지 확이할 수 있다.

다음은 File 객체를 이용한 간단한 예제다. File 객체 f0, f1, f2를 만들어 File 객체의 메소드를 호출하여 출력한다.

import java.io.File;

publicclasstestFile{

publicstaticvoid main(String[] args){

File f0 =newFile("Name.txt");

File f1 =newFile("..");

File f2 =newFile(f1,"test.java");

// 파일 이름

System.out.println("f0.getName() = "+ f0.getName());

// 파일 경로

System.out.println("f1.getPath() = "+ f1.getPath());

// 파일의 절대 경로

System.out.println("f0.getAbsolutePath() = "+ f0.getAbsolutePath());

// 파일의 상위 디렉토리

System.out.println("f1.getParent() = "+ f1.getParent());

// 파일의 존재 여부

System.out.println("f0.exists() = "+ f0.exists());

// 쓰기 가능 여부

System.out.println("f0.canWrite() = "+ f0.canWrite());

// 읽기 가능 여부

System.out.println("f0.canRead() = "+ f0.canRead());

// 디렉토리 인지 여부

System.out.println("f1.isDirectory() = "+ f1.isDirectory());

// 파일이 절대 경로로 지정되었는지 여부

System.out.println("f2.isAbsolute() = "+ f2.isAbsolute());

// 파일이 수정된 시간( long형 )

System.out.println("f0.lastModified() = "+new java.util.Date(f0.lastModified()));

// 파일의 길이

System.out.println("f0.length() = "+ f0.length());

String[] list = f1.list();

// 파일 목록( 디렉토리의 경우 )

System.out.println("f1.list() = {");

for(int i =0; i < list.length; i++)

System.out.println("\t"+ list[i]);

System.out.println("}");

try{

// 기본 경로

System.out.println("f1.getCanonicalPath() = "+ f1.getCanonicalPath());

}catch(Exception e){

e.printStackTrace();

}

}

}

실행화면

f0.getName() = Name.txt

f0.getAbsolutePath() = E:\HYUNKOOK\Workspace\testFile\Name.txt

f1.getPath() = ..

f2.getAbsolutePath() = E:\HYUNKOOK\Workspace\testFile\..\test.java

f1.getParent() = null

f0.exists() = true

f0.canWrite() = true

f0.canRead() = true

f1.isDirectory() = true

f2.isAbsolute() = false

f0.lastModified() = Thu Feb 10 14:10:49 KST 2011

f0.length() = 8

f1.list() = {

.metadata

// …

testDoubleBuffering

testFile

testThread

}

f1.getCanonicalPath() = E:\HYUNKOOK\Workspace

lastModified() 메소드는 가장 최근의 갱신 시간을 long형으로 리턴한다. 따라서 java.util.Data 클래스를 이용해서 Date 객체를 생성하여 출력하였다. 또한 list() 메소드는 File 객체가 디렉토리일 경우에 포함된 파일 목록을 String[]으로 얻을 수 있다.

3. 바이트 입출력 스트림

프로그램에서 입출력은 매우 중요한 부분이다. 가장 기본적인 입출력은 파일 입출력으로, 대부분의 어플리케이션이 데이터를 저장하는 데 파일을 이용한다. 또한, 프로그램 이외에도 네트워크 통신이나 외부 장치와 통신하는 데도 입출력이 필요하다. ( OS의 FS – File System )을 생각해 보자.

앞에서 자바 입출력은 스트림을 기반으로 하는 입출력이라고 했다. 스트림은 바이트를 단위로 하여 순차적으로 입력 또는 출력을 하는 방식이다. 이처럼 기본적인 바이트 단위 스트림 입출력을 저수준 스트림이라고 한다. 저수준의 스트림은 바이트 또는 바이트 배열을 기반으로 데이터를 입출력한다.

운영체제는 파일을 텍스트 파일과 바이너리 파일로 나누어 다룬다. 이러한 구별은 파일을 열 때 지정할 수 있다. 하지만 자바 언어는 모든 파일을 순차적인 바이트의 배열, 즉 InputStream 또는 OutputStream 클래스로 제공되는 스트림으로 처리한다.

입출력 스트림은 크게 입력 스트림과 출력 스트림으로 나뉜다. 입력 스트림은 시작점( 소스 )을 생성자의 인자값으로 하여 생성하고, 출력 스트림은 종료점( 싱크 )을 인자값으로 하여 생성한다. 시작점이 무엇이냐에 따라서 입력 스트림은 바이트 배열( byte array ), 파일( file ), 객체( object ), 파이프( piped ), 문자열 버퍼( string buffer ), 시퀀스( sequence ) 등으로 나눌 수 있다. 출력 스트림은 종료점이 무엇이냐에 따라서 바이트 배열( byte array ), 파일( file ), 객체( object ), 파이프( piped ) 등으로 나눌 수 있다.

이와 같은 기본 스트림 이외에 스트림을 가공하는 필터 스트림이 존재한다. 필터 스트림에는 버퍼( buffered ), 반환형( pushback ), 라인( line number ), 데이터( data ) 스트림 등이 있다. 출력 스트림에 해당하는 필터 스트림에는 버퍼( buffered ), 데이터( data ), 프린트( print ) 스트림 등이 있다.

4. 문자 입출력 스트림

바이트 입출력 스트림이 기본적으로 InputStream과 OutputStream 클래스로부터 제공되는 것과 달리, 문자 기반의 입출력 스트림은 Reader와 Writer 클래스로부터 제공된다.

문자 스트림은 지역코드와 유니코드를 변환하는 변환기를 포함한다. 자바는 유니코드를 지원하지만, 운영체제는 지역코드를 사용하므로 문자 스트림에 이러한 변환기가 반드시 있어야 한다. 리더는 8비트 문자 스트림을 16비트 유니코드 스트림으로, 라이터는 16비트 유니코드 문자 스트림을 적절한 8비트 문자 스트림으로 변환시켜 준다.

입력 스트림에 대응되는 리더에는 소스 종류에 따라 버퍼( buffered ), 입력( input stream ), 라인( line number ), 문자 배열( char array ), 파이프( piped ), 반환형( push back ), 문자열( string ) 리더 등을 들 수 있다. 출력 스트림에 대응되는 라이터에는 싱크 종류에 따라 버퍼( buffered ), 문자 배열( char array ), 프린트( print ), 문자열( string ) 라이터 등을 들 수 있다.

  • 2. 바이트 입출력 스트림

입출력 스트림은 기본적으로 바이트를 기반으로 한 순차적인 접근을 허용한다. 이는 순차적으로 입력하거나 순차적으로 출력하는 것으로 입출력을 처리하는 것이다. 이제 입출력을 위한 클래스 구조를 살펴보자.

1. 입출력 클래스 계층 구조

입출력 스트림 클래스와 관련된 클래스는 여기를 참고하자. http://download.oracle.com/javase/6/docs/api/java/io/package-tree.html

2. 파일 입출력 스트림

파일 입출력 스트림이란 FileInputStreamFileOutputStream 클래스를 이용한 입출력을 말한다. 이들 객체는 생성자 호출 시 인자값으로 File 객체 또는 파일명을 이용한다. 파일에서 입출력 스트림을 얻는 것이 중요하며, 파일 입출력은 기본적으로 파일 입출력 스트림을 사용한다.

import java.io.File;

import java.io.FileOutputStream;

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

import java.io.FileInputStream;

publicclasstestFileStream{

publicstaticvoid main(String[] args){

String filename ="예문.txt";

// File 객체 생성

File file =newFile(filename);

try{

// File 객체로부터 FileOutputStream 객체 생성

FileOutputStream out =newFileOutputStream(file);

// 문자열로부터 getBytes()로 바이트 배열 얻기

out.write("Java Programming\n".getBytes());

out.write("테스트중입니다.\n".getBytes());

out.write("FileInputStream/FileOutputStream\nTest File\n".getBytes());

// 1부터 30까지 byte 단위로 출력

for(int i =0; i <30; i++){

out.write((byte) i);

}

// 파일 닫기를 위해 close() 메소드 호출

out.close();

// 문자열로부터 FileInputStream 객체 생성

FileInputStream in =newFileInputStream(filename);

int b;

// 입력이 끝날 때까지 바이트 단위로 반복적으로 읽기

while((b = in.read())>-1){

System.out.print((char) b);

}

// 파일 닫기를 위해 close() 메소드 호출

in.close();

}catch(Exception e){

e.printStackTrace();

}

}

}

실행화면

Java Programming

FileInputStream/FileOutputStream

Test File

테스트중입니다.

_

문자열 "예제.txt"로부터 File 객체를 생성하고, File 객체로부터 FileOutputStream 객체를 생성한다. 여기에 write() 메소드를 이용해서 출력을 하는데, 기본적으로 byte 또는 byte[] 단위로 출력되기 때문에 문자열 출력은 getByte() 메소드를 이용해서 바이트 단위로 전환한다.

또한, 1부터 30까지의 바이트형 수를 for 문을 이용하여 차례대로 출력한 뒤 close() 메소드를 호출하여 파일 출력을 종료한다. 다시 이번에는 문자열 filename으로부터 직접 FileInputStream 객체를 생성해서 방금 저장한 데이터를 바이트 단위로 입력받아 화면에 출력한 뒤 종료한다. 우선 화면에 출력되는 것은 문자로 변환되어서 출력되며, 1~30 코드에 해당하는 문자는 특수 문자므로 이에 적절한 문제가 화면에 출력된다.

3. 버퍼 입출력 스트림

버퍼 입출력을 이용하면 데이터의 입출력 속도를 높일 수 있다. - 다음에 -

4. 필터 입출력 스트림

필터 입출력 스트림은 다른 종류의 입출력 스트림을 하나로 연결해서 처리하는 역할을 한다. - 다음에 -

데이터 입출력 DataInputStream/DataOutputStream

< 짝을 이루는 메소드 >

DataInputStream 메소드

DataOutputStream 메소드

byte b = dis.readByte();

dos.wirteByte(b);

char c = dis.readChar();

dos.wirteChar(c);

short s = dis.readShort();

dos.wirteShort(s);

int i = dis.readInt();

dos.wirteInt(i);

long l = dis.readLong();

dos.wirteLong(l);

float f = dis.readFloat();

dos.wirteFloat(f);

double d = dis.readDouble();

dos.wirteDouble(d);

Boolean bl = dis.readBoolean();

dos.wirteBoolean(bl);

String str = dis.readString();

dos.wirteString(str);

import java.io.*;

publicclasstestDataStream{

publicstaticvoid main(String[] args){

String filename ="Korean.bin";

try{

// a ~ g까지 기본형 변수 설정

int a =1;

float b =(float)11.4;

short c =(short)6213;

long d =1300012;

double e =5919301931.121213049484;

byte f =(byte)3;

char g ='S';

System.out.println("Initial Data");

System.out.println("a (int) = "+ a);

System.out.println("b (float) = "+ b);

System.out.println("c (short) = "+ c);

System.out.println("d (long) = "+ d);

System.out.println("e (double) = "+ e);

System.out.println("f (byte) = "+ f);

System.out.println("g (char) = "+ g);

// 기본형 변수 출력

DataOutputStream out =newDataOutputStream(newFileOutputStream(filename));

out.writeInt(a);

out.writeFloat(b);

out.writeShort(c);

out.writeLong(d);

out.writeDouble(e);

out.writeByte(f);

out.writeChar(g);

out.close();

// 기본형 변수에 데이터 입력

DataInputStream in =newDataInputStream(newFileInputStream(filename));

a = in.readInt();

b = in.readFloat();

c = in.readShort();

d = in.readLong();

e = in.readDouble();

f = in.readByte();

g = in.readChar();

in.close();

// 출력

System.out.println("DataInputStream Data(right)");

System.out.println("a (int) = "+ a);

System.out.println("b (float) = "+ b);

System.out.println("c (short) = "+ c);

System.out.println("d (long) = "+ d);

System.out.println("e (double) = "+ e);

System.out.println("f (byte) = "+ f);

System.out.println("g (char) = "+ g);

// 다시 DataInputStream 객체 생성

in =newDataInputStream(newFileInputStream(filename));

// 역순으로 데이터 입력

g = in.readChar();

f = in.readByte();

e = in.readDouble();

d = in.readLong();

c = in.readShort();

b = in.readFloat();

a = in.readInt();

// 잘못 입력된 변수 출력

System.out.println("DataInputStream Data(wrong)");

System.out.println("a (int) = "+ a);

System.out.println("b (float) = "+ b);

System.out.println("c (short) = "+ c);

System.out.println("d (long) = "+ d);

System.out.println("e (double) = "+ e);

System.out.println("f (byte) = "+ f);

System.out.println("g (char) = "+ g);

}catch(Exception e){

e.printStackTrace();

}

}

}

실행화면

Initial Data

a (int) = 1

b (float) = 11.4

c (short) = 6213

d (long) = 1300012

e (double) = 5.919301931121213E9

f (byte) = 3

g (char) = S

DataInputStream Data(right)

a (int) = 1

b (float) = 11.4

c (short) = 6213

d (long) = 1300012

e (double) = 5.919301931121213E9

f (byte) = 3

g (char) = S

DataInputStream Data(wrong)

a (int) = 2097348691

b (float) = 1.1849933E-25

c (short) = -2547

d (long) = 332803137

e (double) = 1.2549843762898047E-302

f (byte) = 0

g (char) = _

a~g 까지 변수를 각각 int, float, short, long, double, byte, char를 기본형으로 해서 초기값을 저장하고, 이를 DataOutputStream 객체를 이용해서 파일로 출력한 다음 정상적인 순서로 입력하고, 입력 순서를 역순으로 해서 입력한 결과를 출력한 것이다. 당연히 순서가 뒤바뀌면 처음에 저장된 데이터를 복원할 수 없으므로 데이터 입출력에는 순서를 잘 지켜야 한다.

반환형 입력 스트림 PushbackInputStream

- 다음에 -

라인 스트림 LineNumberInputStream/PrintStream

- 다음에 -

바이트 배열 스트림 ByteArrayInputStream

// ByteArrayInputStream

System.out.println("ByteArrayStream Test: ");

byte[] bytes ="이 문장은 ByteArrayInputStream을 위한 문장입니다.".getBytes();

ByteArrayInputStream bin =newByteArrayInputStream(bytes);

int ch;

while((ch = bin.read())>-1){

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

}

실행화면

ByteArrayStream Test:

이 문장�? ByteArrayInputStream을 위한 문장입니다.

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
95 Best and Free Programming Ebooks with Open Source Licenses 가을의 곰을... 2012.02.12 6998
94 Stanford Univ Lecture : Web Applications file 가을의 곰을... 2012.02.11 5895
93 Mobile Web Application과 Webstore 가을의 곰을... 2012.02.11 6675
92 Libpcap File Format 가을의 곰을... 2012.02.05 12147
91 소프트웨어 특허 실제 사례 분석-4 가을의 곰을... 2012.01.23 7063
90 데스크톱 가상화 시장 뜰까 file 가을의 곰을... 2012.01.19 6737
89 MP3 탄생 배경 2. MP3와 디지털 오디오 3. MP3 압축 원리 4. MPEG의 종류 가을의 곰을... 2012.01.18 7525
88 소프트웨어 특허 실제 사례 분석-3 가을의 곰을... 2012.01.12 6364
87 소프트웨어 특허 실제 사례 분석-2 가을의 곰을... 2012.01.12 6775
86 소프트웨어 특허 실제 사례 분석-1 가을의 곰을... 2012.01.12 7063
85 How to run HelloWorld and tests of cocos2d-x on bada file 가을의 곰을... 2012.01.05 6823
84 자바 SSL 사용법 가을의 곰을... 2011.12.30 8013
83 Apache HttpClient로 https 연결 데이터 받기 가을의 곰을... 2011.12.30 10868
82 libpcap 를 이용한 프로그래밍 가을의 곰을... 2011.12.18 6272
81 소스 분석 툴 ( Linux) tools 가을의 곰을... 2011.12.18 11120
80 C 코드 분석 툴 file 가을의 곰을... 2011.12.18 11336
79 [공부] Tcpdump & pcap분석 file 가을의 곰을... 2011.12.08 10687
» 자바 입출력( java stream ) 가을의 곰을... 2011.12.08 6845
77 게임소설 쓰는 법 file 가을의 곰을... 2011.12.04 5572
76 게임소설이란 무엇인가? 위키백과에서 가을의 곰을... 2011.12.04 5870
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED