C#에서 파일 이름, 확장자. 크기, 수정일자 등을 알아낼 수 있습니다.


1. 파일 이름, 확장자 출력

네임스페이스 using System.IO를 포함시켜줍니다. Path 클래스를 사용하면 아래 예제처럼 파일이름을 알 수 있습니다. 이외에도 Path에는 임시폴더를 만들거나 랜덤으로 이름과 확장자를 만들 수도 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.IO;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {            
            string file = @"C:\test\aaa.txt";
            System.Console.WriteLine($"파일이름+확장자 : "
                             + Path.GetFileName(file));
            System.Console.WriteLine($"파일 이름 (확장자없이): " 
                             + Path.GetFileNameWithoutExtension(file));
            System.Console.WriteLine($"확장자 : " 
                             + Path.GetExtension(file));
        }
    }
}
 
cs

- 출력결과 - 

파일이름+확장자 : aaa.txt

파일 이름 (확장자없이): aaa

확장자 : .txt



2. 파일 크기, 접근 일자, 속성 등 출력

위의 예제와 마찬가지로 using System.IO를 포함시켜주어야 합니다.

FileInfo 를 이용해 정보를 얻어올 수 있습니다. 아래 예제와 같이 사용하면 됩니다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.IO;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {            
            string file = @"C:\test\aaa.txt";
            var info = new FileInfo(file);
            System.Console.WriteLine("파일 사이즈: " + info.Length+" Bytes");
            System.Console.WriteLine("생성 시간 : " + info.CreationTime);
            System.Console.WriteLine("수정 시간 : " + info.LastWriteTime);
            System.Console.WriteLine("접근 시간 : " + info.LastAccessTime);
            System.Console.WriteLine("읽기전용 파일 어부 : " + info.IsReadOnly);
            System.Console.WriteLine("디렉터리 이름 : " + info.DirectoryName);
            System.Console.WriteLine("파일 이름 : " + info.Name);
            System.Console.WriteLine("경로+파일 이름 : " + info.FullName);
        }
    }
}
cs


- 출력결과 - 

파일 사이즈: 50 Bytes

생성 시간 : 2018-06-25 오후 8:49:50

수정 시간 : 2018-07-05 오후 9:15:04

접근 시간 : 2018-06-25 오후 8:49:50

읽기전용 파일 어부 : False

디렉터리 이름 : C:\test

파일 이름 : aaa.txt

경로+파일 이름 : C:\test\aaa.txt


아래는 C#에서 파일 및 디렉터리 생성 및 복사 삭제 등에 관한 포스팅 입니다.

2018/07/03 - [닷넷,C#,.NET] - C# 파일 및 디렉터리 생성, 삭제, 복사, 존재여부 검사 등


Posted by 꿈만은공돌
,

C#에서 디렉터리나 파일을 읽고 쓰고 하는등에 클래스에 대해서 알아보자.



1. 디렉터리 존재여부 알기


네임스페이스 using System.IO 를 포함시키고 System.IO.Directory.Exists(string path) 함수를 사용하면 된다.

함수에 이름이 너무 길다면 using static System.IO.Directory; 를 하면 Exists() 만을 사용하면 된다.


아래 예제를 보자. 해당 디렉터리가 있는지 검사하는 예제이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.IO;
using static System.IO.Directory;
 
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {            
            string dir = @"C:\test";
            if (Exists(dir))
            {
                System.Console.WriteLine("해당 폴더 존재");
            }
            else
            {
                System.Console.WriteLine("해당 폴더 없음");
            }
        }
    }
}
cs



2. 디렉터리 만들기, 삭제하기


디렉터리 생성 : System.IO.Directory.CreateDirectory(string path)

삭제 : System.IO.Directory.Delete(string path) 


아래 예제는 해당 디렉터리가 있으면 삭제하고 없으면 생성하는 예제이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.IO;
using static System.IO.Directory;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {
            
            string dir = @"C:\test";
            if (Exists(dir))
            {
                
                Delete(dir);
                System.Console.WriteLine("폴더 삭제");
            }
            else
            {                
                CreateDirectory(dir);
                System.Console.WriteLine("폴더 만들기");
            }
        }
    }
}
cs



3. 파일 존재여부 검사


디렉터리와 다르게 파일을 다루는 것은 좀더 간단하다. File.Exists(string path) 함수를 사용하면된다.

디렉터리와 마찬가지로 네임스페이스 using System.IO 를 포함시켜준다.


아래 예제는 파일이 존재하는지 검사하는 예제이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.IO;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {
        
            string file = @"C:\test\aaa.txt";
            if (File.Exists(file))
            {
                System.Console.WriteLine("해당 파일 존재");
            }
            else
            { 
                System.Console.WriteLine("해당 파일 없음");
            }
        }
    }
}
cs



4. 파일 생성하기, 텍스트 쓰기, 복사


파일을 생성하는 함수는 File.CreateText(string path) 를 사용하여 만들 수 있다.

원형은 다음과 같다. StreamWriter CreateText(string path);

파일복사는 copy함수를 쓰는데 아래와 같은 원형을 가진다. 마지막 파라미터인 overwrite는 true면 해당 파일이 존재하면 덮어쓰기를 한다.

void Copy(string sourceFileName, string destFileName, bool overwrite);


아래 예제는 파일을 만들어서 텍스트를 쓰고 복사를 한다. StreamWriter 객체로 파일로 생성한 파일을 받아서 WriteLine 로 파일에 내용을 쓴다. 그리고 Dispose 함수로 파일을 닫아준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.IO;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {            
            string textFile = @"C:\test\text.txt";
            string copyFile = @"C:\test\copy.txt";
 
            StreamWriter textWrite = File.CreateText(textFile); //생성
            textWrite.WriteLine("abcdefghijk"); //쓰기
            textWrite.Dispose(); //파일 닫기
 
            File.Copy(textFile, copyFile, true); //복사
        }
    }
}
cs



5. 파일 읽기


StreamReader 클래스를 사용하여 파일을 읽을 수 있다. 객체를 생성하여 File.OpenText(String dir)로 파일을 연다.

읽은 내용을 모두 읽는건 ReadToEnd()를 사용한다.

파일을 닫는건 Dispose()를 사용한다.


아래 예제는 이전 예제에서 복사한 copy.txt 파일을 읽어 화면에 출력한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.IO;
 
namespace TEST
{
    class Program
    {
        static void Main(string[] args)
        {            
            string copyFile = @"C:\test\copy.txt";
            StreamReader textReader = File.OpenText(copyFile);
            System.Console.WriteLine(textReader.ReadToEnd());
            textReader.Dispose();
        }
    }
}
 
cs

Posted by 꿈만은공돌
,

 프로그램을 만들다보면 숫자를 랜덤으로 만들어내야 할 때가 있습니다. 이번 포스팅은 C언어와 C++에서 랜덤으로 숫자를 추출하는 방법과 여러 예제를 살펴보겠습니다.


1. rand 함수의 기본 사용 방법


rand 함수를 사용하면 랜덤으로 숫자를 출력할 수 있습니다.


함수 원형은 아래와 같습니다. 

int rand(void)


#include<stdlib.h>로 stdlib.h 헤더파일에 해당 선언이 적혀있습니다. 


해당 함수는 0 부터 32767까지의 숫자 중 하나를 랜덤으로 뽑아냅니다.


여기에 % 연산자를 사용하여 원하는 숫자의 범위를 정합니다.


예를들어 rand() % 10 을 하면 0부터 9까지의 숫자중 하나가 나오게 됩니다.


만약 5부터 10까지의 숫자 중 를 랜덤으로 추출하고 싶다면 


rand() % 6 + 5 를 하면 됩니다. rand() % 6 을 하면 0부터 5까지의 숫자 중 하나이고 거기에 +5를 하면 5부터 10까지의 숫자중 하나가 됩니다.


이렇게 하면 자신이 원하는 숫자를 랜덤으로 추출할 수 있습니다.


아래 사용예제 입니다. 0부터 99까지의 숫자중 랜덤으로 변수 num에 저장하여 출력합니다.

총 3번을 반복합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
 
void main() 
{        
    int num;
    num = rand() % 100;
    printf("rand : %d\n", num);
    num = rand() % 100;
    printf("rand : %d\n", num);
    num = rand() % 100;
    printf("rand : %d\n", num);
}
cs


- 출력결과 -

rand : 41

rand : 67

rand : 34




2. srand 함수를 사용하여 프로그램을 실행할 때마다 다른 난수 출력하기


 하지만 이상한 것은 프로그램을 실행 할 때마다 매번 같은 숫자가 나오게 됩니다.

이것은 프로그램을 실행할 때마다 항상 난수표에 같은 지점에서부터 숫자를 추출하기 때문입니다.

난수표라는 것은 글 가장 마지막에 설명을 써놓았습니다.


 그래서 프로그램을 실행할 때마다 숫자가 다르게 나오게 하고 싶다면 srand 함수를 이용해야 합니다.

아래 함수의 원형 입니다.


void srand( unsigned int seed );


 seed값을 받아 난수표에 시작 지점을 바꾸는 것 입니다. 보통은 seed로 현재의 시간을 unsigned int 로 변환하여 사용하게 됩니다. 그러면 프로그램을 시작하는 시간이 계속 달라지기 때문에 프로그램을 실행할 때마다 다른 수가 추출되게 됩니다.


srand 함수를 사용하기 위해서는 #include<time.h>를 추가하여야 합니다.


아래 사용예제 입니다. 위의 예제와 같지만 프로그램이 시작할때 scanf() 를 사용합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
 
void main() 
{        
    int num;
    srand(time(0));
    num = rand() % 100;
    printf("rand : %d\n", num);
    num = rand() % 100;
    printf("rand : %d\n", num);
    num = rand() % 100;
    printf("rand : %d\n", num);
}
cs


출력결과가 매번 다릅니다.




3. 알파벳 랜덤으로 출력


아래 예제는 응용한 것으로 알파벳 소문자 a부터 z중 하나를 출력하는 예제입니다.

알파벳 개수가 26개기 때문에 rand() % 26 을하고 +'a' 를 합니다. 아스키2 코드를 이용 하는 것입니다.

그러면 a부터 z중 하나의 숫자가 출력됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
 
void main() 
{        
    int i;
    char ch;
    srand(time(0));
    for (i = 0; i < 10; i++) {
        ch = rand() % 26 + 'a';
        printf("rand : %c\n", ch);
    }
}
cs


- 출력결과 -

rand : e 

rand : s 

rand : b 

rand : f 

rand : i 

rand : p 

rand : n 

rand : b 

rand : j 

rand : d 






4. 로또 번호 추첨


1부터 45까지의 숫자를 중복없이 6개 출력하는 로또 번호추첨 예제이다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
 
#define MAX 45 //1부터 45 숫자
#define NUMBER //6개 숫자출력
 
void main() 
{        
    int i, tmp;
    int save[NUMBER];
    int count = 0;
    int isSame = 0;
    srand(time(0));
    
    //숫자 추출
    while (count < NUMBER) {
        isSame = 0;
        tmp = rand() % MAX + 1;//1부터 45 출력
        for (int i = 0; i < count; i++) { //중복검사
            if (tmp == save[i]) { //중복이 있을때
                isSame = 1;
                break;
            }
        }
        if (isSame == 0) { //중복없음
            save[count] = tmp;
            count++;
        }
    }
 
    //결과 출력
    printf("추첨 숫자 : ");
    for(i =0; i < NUMBER; i++)    
        printf("%d ", save[i]);
    printf("\n");    
}
cs


- 출력결과 -

추첨 숫자 : 35 15 29 19 27 38




5. 프로그래밍 언어에서 난수(랜덤)란?


 추가로 사실 대부분에 프로그램에서 사용하는 랜덤 함수들은 정밀하게는 완벽한 랜덤이 아닙니다. 난수표 라고해서 특성 숫자들이 적힌 테이블이 있는데 이 테이블들을 순서대로 출력하는 것 입니다. 

 예를들어 1 5 4 2 0 3 7 6 란 숫자가 있으면 1을 선택하고 그 다음에는 5를 선택하고 이런식으로 차례대로 숫자를 선택합니다. 이와 같은 방식으로 C와 C++에서는 0부터 32767 까지의 숫자들이 난수표에 적혀 있습니다. 그래서 엄밀하게는 완벽한 랜덤이라고 할 수 는 없습니다.

 따라서 보안이 중요한 곳이나 이런데서는 랜덤함수를 사용할때 주의가 필요합니다. 랜덤함수를 사용하여 추출한 결과를 보면 다음 수를 예측하거나 하는 방법으로 해킹등을 할 수도 있기 때문입니다.

Posted by 꿈만은공돌
,

JAVA에서 File CLASS는 파일이 존재하는지, 디랙토리가 존재하는지, 사이즈가 몇인지 등을 알 수 있는 편리한 클래스 입니다. 특별한 라이브러리 추가 없이 사용가능하기 때문에 편리합니다.

특히 특정 폴더 밑에 모든 파일들을 삭제하거나 검색하는 등에 기능으로 사용하기 좋습니다.



우선 import java.io.File; 로 import를 시킵니다.


1. exists 함수

파일이 존재하는지 여부를 알 수 있습니다.

반환결과가 boolean으로 파일이 존재하면 참, 없으면 거짓을 반환 합니다.


1
2
3
4
5
6
File f = new File("C://test/a.txt");
if(f.exists()) {
     System.out.println("파일 존재");
else {
      System.out.println("파일 없음");            
}
cs


2. length 함수

file의 사이즈를 측정하는 함수 입니다. 바이트 사이즈 크기를 변수타입 long으로 반환합니다. 


1
2
3
4
5
6
7
    File f = new File("C://test/a.txt");
    if(f.exists()) {
        long len = f.length();
        System.out.println("file Size : " + len);
    } else {
        System.out.println("파일 없음");            
    }
cs



3. isFile 함수

파일인지를 검사하는 함수입니다. 파일이 존재하지 않거나 디렉토리이면 false를 반환, 파일이면 true 반환합니다.


1
2
3
4
5
6
    File f = new File("C://test/");
    if(f.isFile()) {
        System.out.println("파일");  
    } else {
        System.out.println("파일이 아님");            
    }
cs



4. isDirectory 함수

디렉토리인지를 검사하는 함수 입니다. 디랙토리이면 true를 반환하고 파일이거나 존재재하지 않으면 false를 반환합니다.


1
2
3
4
5
6
    File f = new File("C://test/");
    if(f.isDirectory()) {
        System.out.println("디랙토리");  
    } else {
        System.out.println("디랙토리 아님");            
    }
cs



5. isHidden 함수

숨김파일인지를 검사하는 함수 입니다. 파일이나 디랙토리가 숨김으로 되어있으면 true를 반환하고 아니면 false를 반환합니다.


1
2
3
4
5
6
File f = new File("C://test/a.txt");
if(f.isHidden()) {
    System.out.println("숨겨진 파일");  
else {
    System.out.println("숨겨진 파일이 아님");            
}
cs


6. getName 함수

파일에 이름을 반환하는 함수 입니다. 앞에 파일 경로를 제외하고 파일이름만 String 타입으로 반환 합니다.


1
2
3
4
5
File f = new File("C://test/a.txt");
if(f.isFile()) {
    String name = f.getName();
    System.out.println("File Name : " + name);
}
cs


7. getPath 함수

파일의 전체 경로와 이름을 반환하는 함수 입니다.


1
2
3
4
5
File f = new File("C://test/a.txt");
if(f.exists()) {
   String path = f.getPath();
   System.out.println("File Path : " + path);
}
cs



8. listFiles 함수

해당 디랙토리 아래 어떤 파일이나 디렉토리들이 있는지를 반환하는 함수 입니다.

File배열로 반환합니다. 아래 예제를 보면 C://test/ 디렉토리 아래에 있는 모든 파일과 디렉토리를 반환하게 됩니다.


1
2
3
4
5
6
File f = new File("C://test/");
if(f.isDirectory()) {
    File[] fList = f.listFiles();
    for(int i=0; i < fList.length; i++)
        System.out.println(fList[i].getName());
}
cs


9. mkdir 함수

디랙토리 만들기 함수 입니다. 아래 예제대로면 C://test/test2 로 test2 디렉토리를 를 만들게 됩니다.

그러나 C://test 폴더가 존재하지 않으면 실패하게 됩니다. 이럴땐 mkdirs을 사용해야합니다.

결과로 성공여부를 boolean 을 반환합니다.


1
2
3
4
5
6
7
File f = new File("C://test/test2");
boolean result = f.mkdir();
if(result)
   System.out.println("디렉토리 만들기 성공");
else
   System.out.println("디렉토리 만들기 실패");
 
cs




10. mkdirs 함수

위의 9번 mkdir과 거의 같은 기능을 하지만 C://test/test2 에서 상위 폴더들이 없으면 상위폴더들까지 만들게 됩니다.


1
2
3
4
5
6
7
File f = new File("C://test/test2");
boolean result = f.mkdirs();
if(result)
   System.out.println("디렉토리 만들기 성공");
else
   System.out.println("디렉토리 만들기 실패");
 
cs



이외에도 몇가지더 존재하지만 대부분 함수이름을 보면 기능이나 사용방법을 추측해볼 수 있습니다.



Posted by 꿈만은공돌
,



스페인 - 파리 여행 일정 입니다.

2017년 12월 3일부터 총 9박11일 다녀왔습니다.


스페인 : 바르셀로나->세비야->마드리드(세고비야) 6박 7일

파리 :  3박4일


날씨는 스페인에서는 한국보단 조금 따뜻하고 특히나 세비야는 외투가 필요없을정도에 날씨였습니다.

파리는 비가많이오고 그래서 날씨가 좀 쌀쌀했습니다. 한국과 비슷한 정도였던 것 같습니다. 


물가는 스페인은 한국과 비슷한 수준인데 파리는 한국보단 좀더 비싼편이었습니다.


 

 

숙소

시간

일정

 

1일차

 

13:40

18:30

인천공항 출발

바르셀로나 공항 도착

카탈로니아 아빈요

Catalonia Avinyó

2일차

8:50

 

19:00

가우디 투어 (까사 비센스 > 구엘공원 > 까사 바뜨요 > 까사 밀라 > 성바울 병원 > 성가족 성당)

카탈루냐 음악당야경투어 중 선택

3일차

오전

17:55

19:30

바르셀로나 관광(구시가지)

바르셀로나 비행기 탑승

세비야 도착

포사다 델 루세로

Hotel Posada del Lucero

4일차

저녁

세비야 관광(세비야 대성당 -> 스페인광장)

플라맹고 감상(세비야 대성당 근처)

5일차

10:45

13:15

오후

세비야 기차 탑승

마드리드 도착

마드리드 관광(솔광장산 미겔 시장왕립극장왕궁스페인 광장)

7이슬라스 호텔

6일차

9:00

 

저녁

세고비야 당일치기 여행

3호선과 6호선 Moncloa 버스터미널 (몬클로아 역)

마드리드 관광저녁식사

7일차

14:05

16:05

저녁

마드리드 비행기 탑승

파리 도착(파리오를리 공항)

에펠탑 야경

르 마르퀴스 에펠

8일차

08:50

12:00

루브르 오전 투어(3시간)

파리시내 관광(노트르담 성당몽마르트개선문)

9일차

08:30

15:00

17:00

쇼핑

오르세 미술관파리 에펠탑 관광

유람선(바튜무슈)

10일차

13:10

파리(샤를 드 골 공항)에서 출발

11일차

 

08:10

인천 공항 도착

 


Posted by 꿈만은공돌
,

전북 무주군 무주읍 버스터미널 시간표 입니다.

2018년 6월 20일 기준입니다.

무주에 방문하시는 분들 참고해주세요.


무주읍 터미널 위치입니다.





군내버스 시간표 입니다.





시외버스(직행) 시간표 입니다.


Posted by 꿈만은공돌
,

LINQ란 Language Integrated Query 라고해서 특정 데이터들에서 Query를 하여 데이터를 빠르고 편리하게 추출하는 방식이라 할 수 있다. 해당기능은 C# 3.0부터 추가가 되기 시작한 문법이다. 기본적으로 람다표현식을 사용하여 간결하고 가독성 좋게 작성 가능하다. Query를 하는데에는 SQL을 사용한다. SQL 이란 Structured Query Language의 약자이다. 


LINQ는 이러한 SQL의 문법을 가지고 다양한 쿼리를 통해 데이터를 가공하고 집계하는 등에 사용된다. 전통적인 방싱그로 for문과 if문을 가지고 특정 데이터들을 가공하고 집계내는 것도 가능하다. 하지만 LINQ를 이용하면 빠르고 정확하게 데이터를 찾는 것이 가능하다. 그리고 더욱 중요한 가독성이 좋다. 문장을 서술 하듯 질의를 하기 때문에 for와 if문을 사용하는 방식보다 가독성이 좋아 실수를 줄이고 유지보수가 쉽다.


LINQ에 자세한 내용은 아래 링크를 참고하자.

http://hijuworld.tistory.com/56



LINQ는 기본적으로 쿼리를 실행하는데 1개의 스레드를 사용한다. 즉 cpu 하나만을 사용해서 처리한다.

하지만 병렬 LINQ(PLINQ)는 여러개의 스레드를 사용해서 쿼리를 실행한다. cpu에 갯수가 많을수록 많은 스레드를 만들어 처리한다.


물론 멀티 스레드가 싱글 스레드를 사용하는 것보다 속도가 더 빠르지 않다. 그래서 무조건 병렬 Linq를 사용하는 것보단 실제 테스트를 해보고 상황에 맞게 판단해서 사용하도록 하자.


아래예제는 1부터 5억까지의 수를 각각 2.1로 나누어 하나의 배열로 만드는 LINQ를 작성하고 해당 LINQ에 처리 시간을 측정하도록 했다. 싱글 스레드를 사용하는 방식이다.


시간측정에 Stopwatch 클래스를 사용했다. 시간측정에관한 자세한 내용은 아래 링크를 참고하자.

C# Stopwatch 클래스를 사용하여 프로그램 실행 시간 측정 하기 : http://hijuworld.tistory.com/18 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace LINQ_TEST
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();//시간측정 객체
            IEnumerable<int> bigNumber = Enumerable.Range(1, 500_000_000);
            Console.Write("아무키나 입력하시오.");
            Console.ReadLine(); //키입력받기
            stopwatch.Start(); //시간측정 시작            
            var result = bigNumber.Select(number => number/2.1).ToArray();
            stopwatch.Stop(); //시간측정 끝
            System.Console.WriteLine("time : " +
                           stopwatch.ElapsedMilliseconds + "ms");
        }
    }
}
 
cs

출력결과
아무키나 입력하시오.
time : 3693ms

아래 리소스 사용량을 보자. 스래드를 8개까지 사용할 수 있지만 4번째 하나만을 사용한 것을 볼 수 있다. 








병렬LINQ를 만들기 위해서는 AsParallel 을 사용하면 된다. 아래 예제를보자. 이전에 예제와 거의 같지만 bigNumber 다음에 AsParallel 함수를 사용하여 병렬처리되도록 한것을 볼 수 있다. 나머지 코드는 모두 동일하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Ch09_PLINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();//시간측정 객체
            IEnumerable<int> bigNumber = Enumerable.Range(1, 500_000_000);
            Console.Write("아무키나 입력하시오.");
            Console.ReadLine(); //키입력받기
            stopwatch.Start(); //시간측정 시작            
            var result = bigNumber.AsParallel()
                            .Select(number => number/2.1).ToArray();
            stopwatch.Stop(); //시간측정 끝
            System.Console.WriteLine("time : " +
                           stopwatch.ElapsedMilliseconds + "ms");
        }
    }
}
 
cs

출력결과
아무키나 입력하시오.
time : 17602ms

아래 cpu 리소스 사용량을 보자. 8개의 스래드가 정상적으로 동작하는 것을 볼 수 있다.


하지만 이상하게 출력결과를 보면 병렬 링큐를 사용했을때 오히려 시간이 더 걸리는 것을 볼 수 있다. 데이터의 갯수를 다르게해도 결과는 같다. 정확한 이유는 알 수 없지만 무조건 병렬 처리를 한다고해서 속도가 향상되는것은 아닌 것을 알 수 있다.

정확한 원인을 알게되면 다음에 포스팅하도록 하겠다.


자료 참고 : 크로스 플랫폼 개발을 위한 c#과 닷넷 코어 2.0(에이콘 출판) 서적 


Posted by 꿈만은공돌
,

메모리를 동적으로 할당 받는 이유는 일반 변수는 컴파일 단계에서 변수의 크기가 정해지기 때문에 프로그램이 실행 되면서 얼마만큼의 배열크기를 사용하게 될지 정확히 알 수 없기 때문에 넉넉하게 할당 받는다. 그래서 프로그램이 실행도중에 사용자가 원하는 만큼 메모리를 할당 받을 수 있다면 메모리 낭비가 줄어들고 프로그램도 안정적으로 동작이 된다. 그래서 나온 개념이 메모리 동적 할당이다.

C언어에는 Heap 영역에 사용자가 원하는 크기만큼 메모리를 할당받아 사용할 수 있다.


그것을 지원하는 3가지 함수가 있는데 malloc, calloc, realloc 이다. 이 포스팅에서는 이 3가지 함수에 차이점에 대해서 배워보도록 하자. 기본적으로 malloc 을 많이 사용하지만 다른 함수들도 알아 두면 유용할때가 많다.


그리고 참고로 메모리를 해제하는 함수는 free이다. 메모리를 할당하고 해제하지 않으면 나중에 사용할 heap 영역에 크기가 부족해 프로그램이 정상동작하지 않을 수 있다.


우선 malloc과 free에 기본적인 사용방법은 아래 링크를 참고하자. 정확히 이해하지 않으면 이번 포스팅이 어려울 수 있다.


C/C++ malloc, free를 사용한 메모리 할당 및 해제 : http://hijuworld.tistory.com/59


그리고 메모리 할당과 해제를 하는 원리는 아래 링크를 참고하자.


C, C++ 에서 동적 메모리의 할당과 해제 원리 : http://hijuworld.tistory.com/28





malloc과 calloc의 차이에 대해서 알아보자.


1. 할당받을 메모리 사이즈를 받는 파라미터의 갯수가 다르다.

2. calloc은 메모리 할당을 받고 0으로 초기화 한다.



우선 함수의 선언을 보면 아래와 같다.


void *malloc(size_t size);

void *calloc(size_t num, size_t size);


malloc은 메모리를 할당받을 사이즈 하나만을 파라미터로 받는 반면

calloc은 메모리를 할당받을 사이즈에 그 메모리를 몇개를 할당 받을지 갯수도 파라미터로 받는다.

둘다 void 포인터를 반환하는데 그 이유는 할당한 메모리를 어떤 크기로 잘라서 사용할지는 그때그때 다르기 때문에 사용자가 강제형변환을 통해 사용하면 되기 때문이다. 


아래 간단한 예제를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
 
int main() {        
    int *pi1; 
    int *pi2;
 
    pi1 = (int *)malloc(sizeof(int* 3); //할당
    pi1[0= 1;
    pi1[1= 5;
    pi1[2= 8;
    
    pi2 = (int *)calloc(3sizeof(int)); //할당
    pi2[0= 1;
    pi2[1= 5;
    pi2[2= 8;    
 
    free(pi1); //메모리 해제
    free(pi2); //메모리 해제
}
cs


pi1 은 malloc으로 할당을 받고 pi2 는 calloc으로 할당을 받았다. 

파라미터의 갯수 말고도 더 큰 차이가 있다.

바로 calloc은 메모리를 할당과 동시에 0으로 초기화 하는 것이다.


아래 예제를 보자. 모두 할당만 하고 값을 출력시켜 보았다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdlib.h>
 
int main() {        
    int *pi1; 
    int *pi2;
 
    pi1 = (int *)malloc(sizeof(int* 3); //할당
    printf("malloc : %d %d %d\n", pi1[0], pi1[1], pi1[2]);
    
    pi2 = (int *)calloc(3sizeof(int)); //할당
    printf("calloc : %d %d %d\n", pi2[0], pi2[1], pi2[2]);
 
    free(pi1); //메모리 해제
    free(pi2); //메모리 해제
}
cs



출력결과

malloc : -842150451 -842150451 -842150451

calloc : 0 0 0                                          


할당하면서 0으로 초기화가 되기때문에 상황에 따라 편리할 수 있다.


realloc에대해서 알아보자.

realloc은 malloc이나 calloc으로 할당받은 메모리의 사이즈를 변경할 때 사용한다.


함수선언은 아래와 같다.

void *realloc(void *block, size_t size);


파라미터로 기존에 할당받았던 메모리를 전달하고 다음 파라미터로 새로 할당 받을 size를 전달한다.


아래 예제를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
 
int main() 
{        
    int i;
    int *pi = (int *)malloc(sizeof(int* 3); //4x3 메모리 할당
    for (i = 0; i < 3; i++)
        pi[i] = i * 4;
    for (i = 0; i < 3; i++)
        printf("pi[%d] : memory %d %d\n", i, &pi[i], pi[i]);
    printf("-----------------------------\n");
 
    pi = (int *)realloc(pi,sizeof(int* 5); //4x5 메모리 재할당
    for (i = 3; i < 5; i++)
        pi[i] = i * 4;
    for (i = 0; i < 5; i++)
        printf("pi[%d] : memory %d %d\n", i, &pi[i], pi[i]);
    printf("-----------------------------\n");
 
    free(pi); //메모리 해제
}
cs


출력결과

pi[0] : memory 9457232 0  

pi[1] : memory 9457236 4  

pi[2] : memory 9457240 8  

-----------------------------  

pi[0] : memory 9457232 0  

pi[1] : memory 9457236 4  

pi[2] : memory 9457240 8  

pi[3] : memory 9457244 12 

pi[4] : memory 9457248 16 

-----------------------------  


처음 4X3 메모리를 할당받았고 그다음에는 4X5 메모리를 재할당 받았다.

재할당 받은 뒤에 기존에 할당받았던 값 이외에 값인 4번째, 5번째에만 값을 넣어준다.

재할당 받은 뒤에도 기존에 값은 정상적으로 존재하는 것을 확인할 수 있다.

단순히 메모리 사이즈만 변경하는 것이 아닌 내용물도 복사를 한다.

 

그리고 메모리의 주소값이 같은것을 볼 수 있는데 이것은 보장하지는 않는다.

완전 새로운 메모리에 값을 새로 할당받아 값을 복사할 수도 있다.


아래 예제를 보자. 메모리를 기존보다 훨씬 크게 할당한 것을 볼 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
 
int main() 
{        
    int i;
    int *pi = (int *)malloc(sizeof(int* 30000); // 메모리 할당
    for (i = 0; i < 3; i++)
        pi[i] = i * 4;
    for (i = 0; i < 3; i++)
        printf("pi[%d] : memory %d %d\n",i,&pi[i],pi[i]);
    printf("-----------------------------\n");
 
    pi = (int *)realloc(pi,sizeof(int* 5000000); // 메모리 재할당
    for (i = 3; i < 5; i++)
        pi[i] = i * 4;
    for (i = 0; i < 5; i++)
        printf("pi[%d] : memory %d %d\n", i, &pi[i], pi[i]);
    printf("-----------------------------\n");
 
    free(pi); //메모리 해제
}
cs

출력결과

pi[0] : memory 17674192 0 

pi[1] : memory 17674196 4 

pi[2] : memory 17674200 8 

-----------------------------  

pi[0] : memory 21880896 0 

pi[1] : memory 21880900 4 

pi[2] : memory 21880904 8 

pi[3] : memory 21880908 12

pi[4] : memory 21880912 16

----------------------------- 


메모리의 주소값이 달라진 것을 볼 수 있다. 하지만 0, 4, 8은 잘 복사된 것을 볼 수 있다.




Posted by 꿈만은공돌
,

동적 메모리 할당은 사용자가 프로그램이 실행도중 원하는 메모리의 크기를 할당하여 사용하는 것이다.

프로그래머가 코드를 작성할 당시에 정확히 얼마에 메모리가 필요한지 알 수 없기때문에 프로그램 실행도중 필요한 만큼만 할당받기 때문에 메모리 낭비를 줄일수 있다.

포인터가 사용되기 때문에 포인터에 대한 이해가 낮으면 조금 어려울 수 있는 내용이다. 그래도 계속 보다보면 적응이 될 것이다.


C언어에서는 힙영역에 사용자가 메모리를 동적 할당하는 3가지 함수인 malloc, calloc, realloc 이 있고

메모리를 해제하는 함수인 free가 있다.


메모리 할당 및 해제에 관한 원리는 아래 링크를 참고하자.

C, C++ 에서 동적 메모리의 할당(malloc, new)과 해제(free,delete) 원리 : http://hijuworld.tistory.com/28


동적 할당하는 3가지 함수인 malloc, calloc, realloc 의 차이에 대해서는 아래 링크를 참고하자.

C/C++ 동적 메모리할당 malloc, calloc, realloc 함수 비교 및 예제 : http://hijuworld.tistory.com/60





가장 기본인 동적 할당 함수인 malloc에 대해서 알아보자.


#include <stdlib.h> 

void* malloc(size_t size);


선언은 위와 같은 형식이다.

파라미터로 할당할 메모리의 크기를 넘기고 반환형이 void 형 포인터이다.

void 포인터인 이유는 할당받은 메모리를 몇바이트씩 잘라서 사용할지는 그때그때 다르기 때문에 사용자가 형변환을 통해서 사용하면 되기 때문이다. 


간단하게 예제를 보자. 1바이트 메모리를 할당해서 char형 포인터에서 할당한 주소값을 저장한다.

1바이트할당 받은 것을 (char*) 를 사용해서 강제형변환을 한 것을 볼 수 있다. 


1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
 
int main() {        
    char *= (char*)malloc(1); //1바이트 메모리 할당
    *= 'h';
    printf("%d, %c\n",c, *c);//c의 주소값, c의 값 'h'
    free(c); //메모리 해제
}
cs

출력 결과

17674200, h


 할당받은 것을 그림으로 그려보면 아래와 같다. 우선 malloc을 이용해서 힙영역에 0x1000번지에 1바이트에 메모리를 할당 한다. 그리고 스택영역에 선언한 지역변수인 포인터 C가 malloc으로 할당한 주소를 가지고 있는다. 

그리고 해당 포인터를 가지고 *c = 'h'로 malloc으로 할당한 메모리에 문자열을 저장한다.



 파라미터로 사이즈를 넘기기 때문에 위의 예제처럼 직접 숫자를 입력해도 가능하진 하지만 아래 예제와 같이 sizeof 를 써서 할당할 변수의 크기와 그 변수의 갯수를 입력하는것이 휴먼에러를 줄이는 방법이다. char 가 1바이트고 int가 4바이트고 float이 4바이트 라는 보장은 할 수 없다. 컴파일러나 운영체제에 따라서 달라질 수 있기 때문이다. 그래서 가장 안전한 방법인 sizeof() 함수를 이용해서 해당 변수에 크기를 그때그때 검사해주는 방법이 좋다. 


1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
 
int main() {        
    char *= (char*)malloc(sizeof(char)); //char 변수 하나의 메모리 할당
    *= 'h';
    printf("%d, %c\n",c, *c);//c의 주소값, c의 값 'h'
    free(c); //메모리 해제
}
cs

비슷한 예제로 int형 변수 4개를 할당받아보자. int에 크기에 4개를 곱한 사이즈를 할당 받았다.

그리고 (int *)로 형변환을 시켜서 i[1] 등을 했을때 4바이트씩 메모리를 증가시키게 된다. 그래서 아래와 같이 배열처럼 사용을 하면 된다. i[1] 은 *(i+1)과 완벽하게 같은 말이다. 


1
2
3
4
5
6
7
8
9
int main() {        
    int *= (int*)malloc(sizeof(int* 4); //int 사이즈 4개 메모리 할당
    i[0= 5;
    i[1= 1;
    i[2= 10;
    i[3= 20;
    printf("%d %d %d %d\n",i[0],i[1],i[2],i[3]);
    free(i); //메모리 해제
}
cs


출력 결과

5 1 10 20


sizeof(int) * 4를 그림으로 그려보면 아래와 같다.  힙영역에 0x1000번지 부터 총 16바이트에 메모리를 할당 받았다. 그리고 지역변수로 선언산 int형 포인터 변수인 i가 그 시작 주소값을 저장한다. i는 int* 이기 때문에 i는 0x1000번지를 가리키고 i+1을 하면 4바이트가 증가하여 1004번지를 가리키게 된다. 그래서 배열과 같이 사용할 수 있게 된다.


2차원 배열을 메모리로 할당 받아보자.

더블포인터를 이용해서 한번 할당받고 다시 각각의 2차원배열 요소들을 할당 받아야 한다.

아래예제를 보자. 처음보면 상당히 복잡하고 난해할 수 있다. 특히 이중포인터를 사용했기 때문에 쉽게 이해가 가지 않을 수 있다. 이해가 가지 않는다면 우선 해당 코드를 복사해서 사용하고 차차 이해해도 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main() {        
    int **ppi = (int**)malloc(sizeof(int** 3); //int* 사이즈 3개 메모리 할당
    int i,j;
    for(i = 0; i < 3; i++)
        ppi[i] = (int*)malloc(sizeof(int* 2); //int 사이즈 2개 메모리 할당
    
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 2; j++) {
            ppi[i][j] = (i + 1) * (j + 1);
        }
    }
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 2; j++) {
            printf("%d ", ppi[i][j]);
        }
    }
    printf("\n");
    
    for (i = 0; i < 3; i++)
        free(ppi[i]); //메모리 해제
    free(ppi); //메모리 해제
}
cs


출력결과

1 2 2 4 3 6


그리고 메모리 해제역시 2차원배열이기 때문에 각 요소들을 해제하고 2차원배열을 해제해줘야 한다.



Posted by 꿈만은공돌
,


 정규 표현식이라는 표현식을 이용하여 패턴이 매칭하는지 검사 할 수 있다. 예를들어 어떤 문자열이 A부터 C사이에 글자로 시작하면서 5글자이내의 글자인지를 검사하거나 해당 문자열이 숫자로만 이루어지고 10글자 이내의 글자인자를 검사할 수 있다. 정규표현식을 잘 작성하면 해당 문자열이 전화번호형식인지 이메일 형식인지 등을 쉽게 검사할 수 있다. 구글링을 통해 해당 정규표현식은 쉽게 찾을 수 있다.

 정규 표현식을 사용하여 패턴 매칭을 하는 것이 속도도 빠르고 정확하다. 사용자가 코드를 아무리 잘짜더라도 정규표현식을 이용하여 패턴 매칭을 하는 것보다 빠르기는 힘들다.

아래 링크는 정규 표현식을 정리한 위키백과이다. 참고하도록 하자.

https://ko.wikipedia.org/wiki/%EC%A0%95%EA%B7%9C_%ED%91%9C%ED%98%84%EC%8B%9D


 프로그래머들이 많이 사용하고 유용하기 때문에 많은 언어에서는 쉽게 정규표현식을 사용하여 패턴매칭을 할 수 있도록 언어차원에서 라이브러리를 지원해준다.

 JAVA 에서도 정규식을 사용하여 패턴 매칭을 할 수 있다.



간단히 핵심을 정리하자면 아래와 같다. 정말 중요하고 기본적인 내용만을 정리했다. 좀더 자세한 내용은 위에서 소개한 위키를 참고하도록 하면 된다.

. : 하나의 문자를 의미한다.
예제 : A.B 패턴은 AAB(일치), A1B(일치), AAB(불일치), AB(불일치) 이다.

? : 아무문자도 없거나 하나의 문자 있는 것을 의미한다.

예제 : A?B 패턴은 AAB(일치), AB(일치), AAA(불일치), AAAB(불일치) 이다.


* : 0개나 하나이상의 문자가 있는 것을 의미한다.

예제 : A*B 패턴은 AB(일치), AAAAAAAAAAAB(일치), A123B(일치), AAAAAAAAAAAA(불일치) 이다.


+ : +앞에있는 문자가 한번이상 반복됨을 의미한다.

예제 : AB+ 패턴은 AB(일치), ABBBB(일치), A(불일치), ABC(불일치) 이다.


[] : [ ] 사이에 있는 형식이 일치하는것을 의미한다. 즉 [AB] 는 A, B만일치, [A-Z] 는 A부터 Z중 하나의 문자와 일치한다.

예제 : [A-C] 패턴은 A(일치), B(일치), AB(불일치), BC(불일치) 이다.


() : ( ) 사이에 문자가 하나의 묶음이된다. 즉 (ab)+ 는 abababab 와 일치한다.

예제 : (ab) 패턴은 ab(일치), ba(불일치) 이다.


{} : { } 사이에 숫자를 쓰면 그 숫자만큼 패턴이 반복됨을 의미한다.

[A-C]{1,3}는 A,B,C 를 1개에서 3개 조합하면 된다. AAA도 가능하고 A, BA, ABC, CBA도 가능하다.

예제 : [A-C]{1,3} 패턴은 AA(일치), CBC(일치), ADA(불일치), ACCC(불일치) 이다.


[^] : ^다음에 문자를 쓰면  해당 문자를 제외한다는 의미한다.

예제 : [^A-C]D 패턴은 DD(일치), AD(불일치), D(불일치), DDD(불일치) 이다.


JAVA에서 정규표현실을 사용하여 패턴매칭을 하는 예시는 아래와 같다.

2가지의 import도 반드시 시켜줘야 한다. Pattern 클래스는 패턴을 저장하고 Matcher라는 클래스는 검사결과를 저장한다. 그래서 Matcher에 함수인 matches 함수를 사용하여 결과를 boolean 으로 리턴받을 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class RegexTestStrings {
    public static void main(String[] args) {        
         Pattern pattern = Pattern.compile("패턴 입력");  
         Matcher match = pattern.matcher("검사할 문자열"); 
         boolean bool = match.matches();
         if(bool)
             System.out.println("일치");
         else
             System.out.println("불일치");
     }
}
cs


아래는 실제 사용 예제이다.

A부터C사이의 글자로 시작을하고 그다음 글자가 D인 패턴과 일치하는지 검사한다.

AD는 해당 패턴과 일치한다. 따라서 일치가 출력된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class RegexTestStrings {
    public static void main(String[] args) {        
        Pattern pattern = Pattern.compile("[^A-C]D"); 
        Matcher match = pattern.matcher("AD"); 
        boolean bool = match.matches();
        if(bool)
            System.out.println("일치");
        else
            System.out.println("불일치");
    }
}
cs


아래링크는 C#에서의 정규식을 사용한 패턴매칭에 관한 포스팅이다. 참고하도록 하자.

C#에서 정규식을 사용하여 패턴 매칭(Regex, IsMatch) : http://hijuworld.tistory.com/22


Posted by 꿈만은공돌
,