이번에는 파일을 분석해서 이 파일이 어느 종류의 파일인지를 알 수 있는 방법에 대해 알아보겠습니다.
사실 대부분의 경우 확장자가 잘 되어 있기 때문에 이 과정이 필요 없을 수 있습니다.
확장자가 jpg, png bmp 인 경우 그림파일, mp3 wav 인 경우 오디오 파일 avi mp4 인 경우 동영상 파일 등...
컴퓨터를 사용하다 보면 자연스럽게 알게 되는 정보이기 때문이죠.
그런데 흔하지는 않지만 실수 또는 잘못된 방법으로 파일의 확장자가 마음대로 변경된 경우를 경험하신 적 있으신가요?
저도 거의 없었지만 이전 휴대폰의 파일을 백업하고 오랜 기간이 지난 후에 보니 그림과 동영상 파일의 확장자가 001 002 같이 마음대로 바껴있더라고요.
물론 대략 폴더의 위치를 보고 확장자를 jpg 나 mp4로 바꿔서 실행해 보는 방법이 있습니다만
요즘 프로그래밍을 공부하다 보니 근본적으로 이 파일이 무슨 파일인지 알아내는 방법이 있는지, 이를 프로그래밍 할 수 있는 방법이 있을 지 궁금해 졌습니다.
그래서 구글로 검색을 해 본 결과 다음과 같은 프로그램을 찾았습니다.
TrID - File Identifier
http://mark0.net/soft-trid-e.html
위 프로그램은 파일의 내부를 분석해서 파일의 확장자가 무엇인지와 무슨 파일인지를 찾아주는 프로그램입니다. 실행 방식은 윈도우 cmd에서 실행해서 결과를 텍스트로 뿌려줍니다. 내 컴퓨터에서 실행하기 위해서는 아래 다운로드 링크 중에서 실행 파일과 TrIDDefs.TRD package 2개를 다운받은 후 압축을 풀면 됩니다.
저는 아래 그림과 같이 "C:\trid_w32" 폴더에 trid.exe, triddefs.trd 파일을 복사했습니다. 그리고 테스트를 위해 그림파일을 하나 가져와서 파일 이름을 unknownfile 이라고 하고 확장자를 지워버렸습니다.
그럼 cmd에서 실행해 볼까요? 윈도우키+R을 누르면 실행창이 뜨는데요 "cmd"라고 입력한 후에 확인을 클릭하면 됩니다. "C:\trid_w32" 폴더로 이동해서 명령어를 "trid unknownfile"라고 입력하면 아래 그림과 파일 분석 후에 결과가 나오게 됩니다.
이 프로그램의 결과를 visual studio 로 가져와서 원하는 형식으로 출력할 수 있을까요? 검색을 해 본 결과 가능한 것을 확인했습니다.
Process.start: how to get the output?
https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output
이제 프로그래밍을 해보겠습니다.
Visual Studio에서 새로운 프로젝트를 아래 그림과 같이 생성합니다. 프로젝트 이름은 "WindowsFormFileIdentifier" 로 지정하였습니다.
그리고 폼을 꾸며보겠습니다. 우선 기본 폼의 속성을 몇가지 변경합니다.
(Name): Form1 - Text: 파일형식 찾기 / Size: 400, 400
이제 도구들을 추가하고 속성을 변경하겠습니다.
라벨(Label) - (Name): label1 / Location: 20, 20 / AutoSize: True / Size: 137, 12(자동으로 설정됨) / Text: 파일 형식 찾기 프로그램
라벨(Label) - (Name): label2 / Location: 20, 60 / AutoSize: True / Size: 231, 12(자동으로 설정됨) / Text: 1. 오른쪽 버튼을 눌러 파일을 선택합니다.
버튼(Button) - (Name): button1 / Location: 260, 60 / AutoSize: False / Size: 75, 23 / Text: 파일 선택
라벨(Label) - (Name): label3 / Location: 20, 100 / AutoSize: True / Size: 73, 12(자동으로 설정됨) / Text: 선택한 파일:
라벨(Label) - (Name): label4 / Location: 100, 100 / AutoSize: True / Size: 29, 12(자동으로 설정됨) / Text: 없음
라벨(Label) - (Name): label5 / Location: 20, 140 / AutoSize: True / Size: 109, 12(자동으로 설정됨) / Text: 선택한 파일의 정보
자료보기창(DataGridView) - (Name): dataGridView1 / Location: 20, 180 / AutoSize: False / Size: 350, 160
꾸며진 결과는 아래 그림과 같습니다.
외형을 완성했으면 이제 프로그래밍을 해보겠습니다.
파일 선택 버튼을 더블클릭하면 자동으로 이벤트가 추가되고 코드보기 화면으로 전환됩니다.
코드를 작성하기 전에 bin\debug 폴더에 위에서 실행했던 trid.exe, triddefs.trd 2개의 파일을 붙여넣기 해야 합니다.
코드 왼쪽에 있는 솔루션 탐색기 메뉴에서 아이콘 중 모든파일 표시 아이콘을 클릭합니다. 기존에는 프로젝트와 관련이 없는 폴더나 파일은 숨겨져 있는데 이 아이콘을 클릭하면 모든 파일이 나타납니다. bin 폴더 안에 있는 debug 폴더에 커서를 놓고 오른쪽 마우스 버튼을 클릭한 후에 "파일 탐색기에서 폴더 열기" 메뉴를 클릭하면 해당 폴더 파일 탐색기가 열리게 됩니다.
이제 위에서 설명한 2개의 파일을 붙여넣기 하면 아래 그림과 같이 파일이 복사된 것을 확인할 수 있습니다.
이제 프로그래밍으 해보겠습니다. 매서드를 2개 만들겠습니다.
매서드1. 실행파일과 분석할 파일 경로를 활용하여 cmd에서 나왔던 정보를 datatable 형식으로 변환하여 출력해 주는 매서드 입니다.
/// <summary>
/// 선택한 파일에 대한 정보를 DataTable 형식으로 내보냅니다.
/// </summary>
/// <param name="FileName">선택한 파일의 전체 경로</param>
/// <returns></returns>
private DataTable GetResultsFromTridCMDStrings(string FileName)
{
// executableLocation 은 프로젝트 폴더\bin\debug 까지의 폴더입니다.
string executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// exefileLocation 는 executableLocation 안에 있는 실행파일 trid.exe 의 전체 경로입니다.
string exefileLocation = Path.Combine(executableLocation, "trid.exe");
// cmd에서 실행했던 것 처럼 프로세스를 실행하기 위한 설정값이 들어간 process 클래스를 proc라는 변수명으로 생성합니다.
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = exefileLocation,
Arguments = FileName,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
// 출력을 위한 datatable을 생성합니다.
DataTable dt = new DataTable();
dt.Columns.Add("%", typeof(string)); // 확률
dt.Columns.Add("Ext", typeof(string)); // 확장자
dt.Columns.Add("Desc", typeof(string)); // 설명
proc.Start(); // 위에서 생성한 proc를 실행합니다.
while (!proc.StandardOutput.EndOfStream)
{
string line1 = proc.StandardOutput.ReadLine(); // cmd에서 나왔던 결과를 1줄씩 가져옵니다.
if (line1.Contains("%")) // 라인에 %가 있을 경우에만 동작하게 했습니다.
{
string dtcol1 = line1.Split('%')[0]; // 확률정보만 가져옵니다.
dtcol1 += "%";
string dtcol2 = line1.Split('(')[1]; // 확장자(점포함) 정보만 가져옵니다.
dtcol2 = dtcol2.Split(')')[0];
string dtcol3 = line1.Split(')')[1]; // 설명부분만 가져옵니다.
dtcol3 = dtcol3.Split('(')[0];
dt.Rows.Add(dtcol1, dtcol2, dtcol3); // 위의 3가지 정보가 포함된 DataRow를 추가합니다.
}
}
return dt;
}
매서드2. 위에서 제공된 결과를 DataGridView 컨트롤에서 볼 수 있도록 가져옵니다.
/// <summary>
/// 선택한 폴더의 파일 목록을 가져와서 DataGridView 도구에 보여줍니다.
/// </summary>
/// <param name="dt1">선택한 폴더의 파일 목록이 들어있는 DataTable을 입력합니다.</param>
/// <param name="dgv1">결과를 출력할 DataGridView를 선택합니다.</param>
private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1)
{
dgv1.Rows.Clear(); // 이전 정보가 있을 경우, 모든 행을 삭제합니다.
dgv1.Columns.Clear(); // 이전 정보가 있을 경우, 모든 열을 삭제합니다.
foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
{
dgv1.Columns.Add(dc1.ColumnName, dc1.ColumnName); // 출력할 DataGridView에 열을 추가합니다.
}
int row_index = 0; // 행 인덱스 번호(초기 값)
foreach (DataRow dr1 in dt1.Rows) // 선택한 파일 목록이 들어있는 DataTable의 모든 행을 스캔합니다.
{
dgv1.Rows.Add(); // 빈 행을 하나 추가합니다.
foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
{
dgv1.Rows[row_index].Cells[dc1.ColumnName].Value = dr1[dc1.ColumnName]; // 선택 행 별로, 스캔하는 열에 해당하는 셀 값을 입력합니다.
}
row_index++; // 다음 행 인덱스를 선택하기 위해 1을 더해줍니다.
}
foreach (DataGridViewColumn drvc1 in dgv1.Columns) // 결과를 출력할 DataGridView의 모든 열을 스캔합니다.
{
drvc1.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; // 선택 열의 너비를 자동으로 설정합니다.
}
}
위에서 만든 2개의 매서드를 활용하여 버튼클릭 이벤트를 아래와 같이 수정합니다.
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog(); // OpenFileDialog 생성합니다.
openFileDialog1.Multiselect = false; // 여러개 선택 못하게 합니다.
if (openFileDialog1.ShowDialog() == DialogResult.OK) // 파일이 선택된 경우에만 실행되게 합니다.
{
label4.Text = openFileDialog1.FileName; // 선택한 폴더 이름을 label4에 출력합니다.
DataTable dt_filelistinfo = GetResultsFromTridCMDStrings(openFileDialog1.FileName);
ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1);
}
}
전체 코드는 다음과 같습니다.
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Windows.Forms;
using System.Data; // DataTable 사용
using System.IO; // Path 사용
using System.Reflection; // Assembly 사용
using System.Diagnostics; // Process 사용
namespace WindowsFormFileIdentifier
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog(); // OpenFileDialog 생성합니다.
openFileDialog1.Multiselect = false; // 여러개 선택 못하게 합니다.
if (openFileDialog1.ShowDialog() == DialogResult.OK) // 파일이 선택된 경우에만 실행되게 합니다.
{
label4.Text = openFileDialog1.FileName; // 선택한 폴더 이름을 label4에 출력합니다.
DataTable dt_filelistinfo = GetResultsFromTridCMDStrings(openFileDialog1.FileName);
ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1);
}
}
private DataTable GetResultsFromTridCMDStrings(string FileName)
{
생략(매서드1)
}
private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1)
{
생략(매서드2)
}
}
}
이제 실행해 보겠습니다.
실행하면 다음과 같이 나타납니다.
파일 선택 버튼을 클릭하고 예제 파일에 있던 "unknownfile" 을 선택하면 다음과 같이 결과가 출력됩니다.
이제 위의 내용을 활용해서 확장자가 변경되었거나 확실하지 않은 파일이 있다면 이 프로그램으로 찾아서 바꿔주는 프로그래밍을 할 수 있습니다.
감사합니다.