Repository navigation
Expand file tree
/
Copy pathFileAutoCleaner.cs
More file actions
355 lines (312 loc) · 16.1 KB
/
Copy pathFileAutoCleaner.cs
File metadata and controls
355 lines (312 loc) · 16.1 KB
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Configuration;
namespace FileAutoCleaner
{
class Program
{
// Load configuration variables at program start
// 설정 변수들을 프로그램 시작할 때 로드
private static string ConnectionString;
private static string SourceFolderPath;
private static string TempFolderPath;
private static string FileViewName;
private static string TempTableName;
private static int DaysToKeep;
static void Main(string[] args)
{
try
{
Console.WriteLine("파일 관리 프로그램을 시작합니다.");
// Load settings (encrypted settings are also automatically decrypted)
// 설정 로드 (암호화된 설정도 자동으로 복호화됨)
LoadConfiguration();
// 1. Create temp table if it does not exist
// 1. 임시 테이블이 없으면 생성
EnsureTempTableExists();
// 2. Retrieve file list from DB
// 2. DB에서 파일 목록 조회
List<string> dbFiles = GetFileListFromDatabase();
Console.WriteLine($"Retrieved {dbFiles.Count} file records from database.\n데이터베이스에서 {dbFiles.Count}개 파일 정보를 조회했습니다.");
// 3. Retrieve file list from local folder
// 3. 로컬 폴더에서 파일 목록 조회
List<string> localFiles = GetLocalFileList();
Console.WriteLine($"Found {localFiles.Count} files in local folder.\n로컬 폴더에서 {localFiles.Count}개 파일을 찾았습니다.");
// 4. Find files not in DB and move to temp folder
// 4. DB에 없는 파일 찾기 및 임시 폴더로 이동
List<string> filesToMove = localFiles.Except(dbFiles, StringComparer.OrdinalIgnoreCase).ToList();
MoveFilesToTempFolder(filesToMove);
// 5. Delete temp files older than 30 days
// 5. 30일 이상 지난 임시 파일 삭제
DeleteOldTempFiles();
Console.WriteLine("File management tasks completed.\n파일 관리 작업이 완료되었습니다.");
Console.WriteLine("Press any key to exit...\n프로그램을 종료하려면 아무 키나 누르세요...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine($"Error occurred: \n오류 발생: {ex.Message}");
Console.WriteLine(ex.StackTrace);
Console.WriteLine("Press any key to exit...\n프로그램을 종료하려면 아무 키나 누르세요...");
Console.ReadKey();
}
}
/// <summary>
/// Load settings from encrypted configuration file
/// 암호화된 구성 파일에서 설정 로드
/// </summary>
private static void LoadConfiguration()
{
try
{
// Even if ConnectionStrings section is encrypted, ConfigurationManager automatically decrypts it
// ConnectionStrings 섹션은 암호화되어 있더라도 ConfigurationManager가 자동으로 복호화함
ConnectionString = ConfigurationManager.ConnectionStrings["SqlConnection"].ConnectionString;
// AppSettings values are also automatically decrypted
// AppSettings 값도 마찬가지로 자동 복호화됨
SourceFolderPath = ConfigurationManager.AppSettings["SourceFolderPath"];
TempFolderPath = ConfigurationManager.AppSettings["TempFolderPath"];
FileViewName = ConfigurationManager.AppSettings["FileViewName"];
TempTableName = ConfigurationManager.AppSettings["TempTableName"];
// If DaysToKeep is missing or not a number, use default value 30
// DaysToKeep 값이 없거나 숫자가 아닐 경우 기본값 30 사용
if (!int.TryParse(ConfigurationManager.AppSettings["DaysToKeep"], out DaysToKeep))
{
DaysToKeep = 30;
Console.WriteLine("DaysToKeep setting is invalid, using default value 30.\nDaysToKeep 설정값이 유효하지 않아 기본값 30을 사용합니다.");
}
Console.WriteLine("Configuration settings loaded successfully.\n구성 설정을 성공적으로 로드했습니다.");
}
catch (Exception ex)
{
throw new Exception($"Error occurred while loading settings: \n설정 로드 중 오류 발생: {ex.Message}", ex);
}
}
/// <summary>
/// Create temp table if it does not exist
/// 임시 테이블이 없으면 생성하는 메서드
/// </summary>
private static void EnsureTempTableExists()
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
// Check if table exists
// 테이블 존재 여부 확인
string checkTableQuery = @"
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName)
BEGIN
CREATE TABLE [dbo].[" + TempTableName + @"] (
[Id] INT IDENTITY(1,1) PRIMARY KEY,
[FileName] NVARCHAR(255) NOT NULL,
[MovedDate] DATETIME NOT NULL DEFAULT GETDATE()
)
END";
using (SqlCommand command = new SqlCommand(checkTableQuery, connection))
{
command.Parameters.AddWithValue("@TableName", TempTableName);
command.ExecuteNonQuery();
}
}
Console.WriteLine($"Temp table {TempTableName} check complete.\n임시 테이블 {TempTableName} 확인 완료");
}
/// <summary>
/// Retrieve file list from database
/// 데이터베이스에서 파일 목록을 조회하는 메서드
/// </summary>
private static List<string> GetFileListFromDatabase()
{
List<string> fileList = new List<string>();
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
string query = $"SELECT * FROM {FileViewName}";
using (SqlCommand command = new SqlCommand(query, connection))
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Adjust file name column to match actual view
// 파일 이름 컬럼명은 실제 뷰에 맞게 수정 필요
string fileName = reader["FileName"].ToString();
fileList.Add(fileName);
}
}
}
return fileList;
}
/// <summary>
/// Retrieve file list from local folder
/// 로컬 폴더에서 파일 목록을 조회하는 메서드
/// </summary>
private static List<string> GetLocalFileList()
{
if (!Directory.Exists(SourceFolderPath))
{
throw new DirectoryNotFoundException($"Cannot find specified source folder: {SourceFolderPath}\n지정된 소스 폴더를 찾을 수 없습니다: {SourceFolderPath}");
}
return Directory.GetFiles(SourceFolderPath)
.Select(Path.GetFileName)
.ToList();
}
/// <summary>
/// Move files to temp folder and record in DB
/// 파일을 임시 폴더로 이동하고 DB에 기록하는 메서드
/// </summary>
private static void MoveFilesToTempFolder(List<string> files)
{
if (files.Count == 0)
{
Console.WriteLine("No files to move.\n이동할 파일이 없습니다.");
return;
}
// Create temp folder if it does not exist
// 임시 폴더가 없으면 생성
if (!Directory.Exists(TempFolderPath))
{
Directory.CreateDirectory(TempFolderPath);
Console.WriteLine($"Temp folder created: {TempFolderPath}\n임시 폴더 생성: {TempFolderPath}");
}
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
// Commit transaction
// 트랜잭션 커밋
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
foreach (string fileName in files)
{
string sourcePath = Path.Combine(SourceFolderPath, fileName);
string destFileName = fileName; // Initialize with original file name
string destPath = Path.Combine(TempFolderPath, destFileName);
int count = 1;
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
// Check for file existence and append counter if duplicated
while (File.Exists(destPath))
{
destFileName = $"{fileNameWithoutExtension}-{count}{extension}";
destPath = Path.Combine(TempFolderPath, destFileName);
count++;
}
// Move file
// 파일 이동
File.Move(sourcePath, destPath);
// Record in DB
// DB에 기록
string insertQuery = $"INSERT INTO {TempTableName} (FileName, MovedDate) VALUES (@FileName, GETDATE())";
using (SqlCommand command = new SqlCommand(insertQuery, connection, transaction))
{
command.Parameters.AddWithValue("@FileName", destFileName); // Use the potentially modified destFileName
command.ExecuteNonQuery();
}
}
// Commit transaction
// 트랜잭션 커밋
transaction.Commit();
Console.WriteLine($"Moved {files.Count} files to temp folder and recorded in DB.\n{files.Count}개 파일을 임시 폴더로 이동하고 DB에 기록했습니다.");
}
catch (Exception ex)
{
// Rollback on error
// 오류 발생 시 롤백
transaction.Rollback();
throw new Exception($"Error occurred while moving files: {ex.Message}\n파일 이동 중 오류 발생: {ex.Message}", ex);
}
}
}
}
/// <summary>
/// Delete temp files that have passed the specified number of days
/// 이동 후 지정된 일수가 경과한 임시 파일을 삭제하는 메서드
/// </summary>
private static void DeleteOldTempFiles()
{
List<OldTempFile> oldFiles = new List<OldTempFile>();
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
// Query files older than specified period from temp table
// 임시 테이블에서 일정 기간 이상 경과한 파일 조회
string query = $@"
SELECT Id, FileName, MovedDate
FROM {TempTableName}
WHERE DATEDIFF(DAY, MovedDate, GETDATE()) >= @DaysToKeep";
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("@DaysToKeep", DaysToKeep);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
oldFiles.Add(new OldTempFile
{
Id = Convert.ToInt32(reader["Id"]),
FileName = reader["FileName"].ToString(),
MovedDate = Convert.ToDateTime(reader["MovedDate"])
});
}
}
}
if (oldFiles.Count == 0)
{
Console.WriteLine($"No old files to delete (based on {DaysToKeep} days).\n삭제할 오래된 파일이 없습니다({DaysToKeep}일 기준).");
return;
}
// Delete files and DB records in transaction
// 트랜잭션으로 파일 삭제 및 DB 레코드 삭제
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
foreach (var file in oldFiles)
{
string filePath = Path.Combine(TempFolderPath, file.FileName);
// Delete file if exists
// 파일이 존재하면 삭제
if (File.Exists(filePath))
{
File.Delete(filePath);
}
// Delete DB record
// DB 레코드 삭제
string deleteQuery = $"DELETE FROM {TempTableName} WHERE Id = @Id";
using (SqlCommand command = new SqlCommand(deleteQuery, connection, transaction))
{
command.Parameters.AddWithValue("@Id", file.Id);
command.ExecuteNonQuery();
}
}
// Commit transaction
// 트랜잭션 커밋
transaction.Commit();
Console.WriteLine($"Deleted {oldFiles.Count} old files and related records.\n{oldFiles.Count}개의 오래된 파일 및 관련 레코드를 삭제했습니다.");
}
catch (Exception ex)
{
// Rollback on error
// 오류 발생 시 롤백
transaction.Rollback();
throw new Exception($"Error occurred while deleting old files: {ex.Message}\n오래된 파일 삭제 중 오류 발생: {ex.Message}", ex);
}
}
}
}
}
/// <summary>
/// Class to store information about old temp files
/// 오래된 임시 파일 정보를 저장하는 클래스
/// </summary>
class OldTempFile
{
public int Id { get; set; }
public string FileName { get; set; }
public DateTime MovedDate { get; set; }
}
}