1) 02-02 오전 10:00 144,285,696 database_all_total.db - 국토교통부 실거래가 자료 2) 02-02 오전 10:44 196,608 descending_in_base_all.db - 매매최대,최소갭 상위 200개 지역별 저장자료 3) 02-05 오후 08:19 23,379,968 naver_attach_estate_info_file.db - 지번이 포함되어진 네이버아파트 자료 4) 02-01 오전 10:40 24,993,792 naver_estate_info_file.db - 지번이 없는 네이버아파트 자료
1) dotnet new console -o RealEstateFileInsert 2) dotnet new console -o RealEstateDescendingFileInsert 4) dotnet new console -o RealNaverAutoCrollingDataInsert 3) dotnet new winforms -oRealAddressAttachAutoCrollingDataInsert
C#이 지역 변수를 초기화 없이 사용하지 못하도록 막는 이유는 메모리 안전성을 보장하기 위해서입니다. C, C++에서는 초기화되지 않은 변수를 사용할 경우 메모리에 남아 있는 쓰레기 값(Garbage Value) 을 가져와 예상치 못한 동작이 발생할 수 있습니다. C#에서는 이러한 문제를 방지하고 안정적인 실행을 보장하기 위해 지역 변수를 명시적으로 초기화하도록 강제합니다.
3. 명확한 코드 유지
초기화를 강제함으로써 코드의 명확성과 가독성이 향상됩니다. 만약 초기화를 하지 않아도 사용 가능하다면, 프로그래머가 실수로 쓰레기 값을 참조할 가능성이 높아지고, 디버깅이 어려워질 수 있습니다.
4. 예외: out 키워드 사용 시 초기화 필요 없음
일반적인 지역 변수는 반드시 초기화해야 하지만, out 키워드를 사용하면 초기화 없이 메소드에 전달 가능합니다.
void SetValue(out int x) { x = 10; // 반드시 값 할당해야 함 }
void Test() { int number; // 초기화하지 않음 SetValue(out number); // out 매개변수는 초기화 필요 없음 Console.WriteLine(number); // 정상 출력 (10) }
💡 out 키워드는 메소드 내부에서 반드시 값을 설정하도록 보장하므로, 지역 변수를 초기화할 필요가 없습니다.
REQUEST) 거래소 주식 TCP 데이타는 회원사들이 100% 일방적으로 수신만 합니다. 거래소는 일방적으로 송신만 합니다. 그럼 회원사들이 사용하는 수신TCP프로그램을 작성하고 싶습니다. 데이타의 구분자는 3개의 딜리미터로 구분됩니다. 0x0a,0a0d,0xff입니다. c#으로 회원사 수신프로그램을 작성해주세요
RESPONSE-CHAT.GPT)
using System; using System.Net; u
sing System.Net.Sockets; using System.Text; using System.Threading;
class TcpServer { private const int Port = 12345; // 서버 포트 private TcpListener tcpListener; private bool isRunning;
public TcpServer() { tcpListener = new TcpListener(IPAddress.Any, Port); isRunning = true; }
public void Start() { tcpListener.Start(); Console.WriteLine("TCP 서버가 시작되었습니다.");
while (isRunning) { try { // 클라이언트 연결 대기 var tcpClient = tcpListener.AcceptTcpClient(); Console.WriteLine("클라이언트 연결됨.");
// 클라이언트에서 데이터를 수신하는 작업 수행 Thread clientThread = new Thread(() => HandleClient(tcpClient)); clientThread.Start(); } catch (Exception ex) { Console.WriteLine($"오류: {ex.Message}"); } } }
private void HandleClient(TcpClient tcpClient) { NetworkStream stream = tcpClient.GetStream(); byte[] buffer = new byte[1024]; StringBuilder sb = new StringBuilder();
while (true) { try { int bytesRead = stream.Read(buffer, 0, buffer.Length); if (bytesRead == 0) { break; // 연결 종료 }
// 받은 데이터를 문자열로 변환 sb.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead));
// 딜리미터에 맞춰 데이터 분리 string data = sb.ToString(); string[] messages = SplitByDelimiters(data);
foreach (string message in messages) { if (!string.IsNullOrEmpty(message)) { Console.WriteLine($"수신된 메시지: {message}"); } }
// 남은 데이터를 다시 설정 sb.Clear(); sb.Append(data.Substring(data.LastIndexOf(messages[messages.Length - 1]) + messages[messages.Length - 1].Length)); } catch (Exception ex) { Console.WriteLine($"오류: {ex.Message}"); break; } }
tcpClient.Close(); Console.WriteLine("클라이언트 연결 종료."); }
private string[] SplitByDelimiters(string input) { // 3개의 딜리미터에 따라 데이터를 분리합니다. var delimiters = new string[] { "\x0A", "\x0D\x0A", "\xFF" }; var messages = input;
// 딜리미터를 기준으로 데이터를 분리 foreach (var delimiter in delimiters) { messages = messages.Replace(delimiter, "\n"); // 구분자를 줄바꿈 문자로 바꿔서 Split }
2020.01 - 2025.01 까지 국토교통부 실거래자료 입력후에 분석해본 통계결과 기자료)
1. 2020-2025 경기도 안양시 동안구 매매자료 download후에, SQLite에 입력후 조회 2. 2020-2025 서울시 마포구 매매자료 download후에, SQLite에 입력 후 조회 3. 2019-2025 서울시 전체 매매자료 download후에, SQLite에 입력 후 조회
프로그램화) 1. 입력부 2. 조회부
분석결과)
서울은 마포구와 강남구를 조사했는데, 모두 신고가가 최근에 이루어지고 있는것을 확인할수 있었고, 나머지 지역은 2021-2022 저금리시기, 급등기에 이루어진 거래였다는 점입니다. 최근은 똘똘한 한채로 신고가 매매가 이루어 지는것 같고, 그 지역은 서울과 수도권의 알짜단지인것 같습니다.
결론) REAL Version을 사용하지 않아도 REDIS 버퍼를 활용한, 데이타 저장후 처리는 정상적으로 처리되어짐
TRIAL Version 사용시) 2023-10-28 오전 07:44 553,984 ServiceStack.dll 2023-10-28 오전 07:44 33,792 ServiceStack.Interfaces.dll 2023-10-28 오전 07:44 20,480 ServiceStack.ServiceInterface.dll
Exception 발생경우)
정상적인 Insert로직 실행 Exception발생하지 않는 경우는) REDIS로 전송
[2025-01-21 10:22:46]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:47]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:47]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:48]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:48]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:48]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:49]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:49]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:50]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:22:50]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:23:31]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-21 10:24:01]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(Exception):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3.
AppDomain.CurrentDomain.BaseDirectory로 얻은 디렉토리 경로에 /Data/CreateDB.sql 파일의 경로를 추가하려면, Path.Combine() 메서드를 사용하여 경로를 안전하게 결합할 수 있습니다.
다음은 currentDirectory에 /Data/CreateDB.sql 파일의 경로를 결합하고 이를 currentFilename 변수에 저장하는 코드 예시입니다:
using System; using System.IO;
class Program { static void Main(string[] args) { // 현재 실행 중인 프로그램의 경로 (dotnet run 실행 폴더) string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
// 하위 디렉토리와 파일 경로를 결합 string currentFilename = Path.Combine(currentDirectory, "Data", "CreateDB.sql");
// 결과 출력 Console.WriteLine($"현재 파일 경로: {currentFilename}"); } }
설명:
AppDomain.CurrentDomain.BaseDirectory: 현재 실행 중인 프로그램의 경로를 반환합니다.
Path.Combine(): 여러 경로 요소를 결합하여 올바른 경로 문자열을 생성합니다. 이 방법은 운영 체제에 맞는 경로 구분자를 자동으로 사용하므로 \ 또는 /를 직접 처리할 필요가 없습니다.
"Data"는 BaseDirectory의 하위 디렉터리입니다.
"CreateDB.sql"은 그 디렉터리 내의 파일입니다.
결과:
위 코드에서 currentFilename은 currentDirectory 경로와 Data/CreateDB.sql을 결합한 절대 경로를 가지게 됩니다. 예를 들어, currentDirectory가 C:\MyApp\인 경우, currentFilename은 C:\MyApp\Data\CreateDB.sql이 됩니다.
참고:
Path.Combine()은 각 부분을 안전하게 결합하여 운영 체제에 맞는 경로를 생성하므로, 경로 구분자를 직접 추가하거나 처리할 필요가 없어 더 안전하고 권장되는 방법입니다.
class Program { public static void Main() { CHKNM nmm = new CHKNM(); nmm.RUN(); } } class CHKNM { public void RUN() { string currentDirectory = AppDomain.CurrentDomain.BaseDirectory; // 하위 디렉토리와 파일 경로를 결합 string currentFilename = Path.Combine(currentDirectory, "Data", "CreateDB.sql"); string currentEstFilename = Path.Combine(currentDirectory, "Data", "CreateEstateDB.sql");
C:\Users\xterm\Downloads\dotnetconsole90>dotnet run C:\Users\xterm\Downloads\dotnetconsole90\dotnetconsole90.csproj : warning NU1803: 'http://nuget.grapecity.com/nuget' 'HTTP' 원본을 사용하여 'restore' 작업을 실 행하고 있습니다. 비 HTTPS 액세스는 이후 버전에서 제거됩니다. 'HTTPS' 원본으로 마이그레이션하는 것이 좋습니다. C:\Users\xterm\Downloads\dotnetconsole90\dotnetconsole90.csproj : warning NU1803: 'http://nuget.grapecity.com/nuget' 'HTTP' 원본을 사용하여 'restore' 작업을 실 행하고 있습니다. 비 HTTPS 액세스는 이후 버전에서 제거됩니다. 'HTTPS' 원본으로 마이그레이션하는 것이 좋습니다. C:\Users\xterm\Downloads\dotnetconsole90\bin\Debug\net8.0\ C:\Users\xterm\Downloads\dotnetconsole90\bin\Debug\net8.0\Data\CreateDB.sql C:\Users\xterm\Downloads\dotnetconsole90\bin\Debug\net8.0\Data\CreateEstateDB.sql
구분자 방식("N:12345"와 "S:Hello World")을 적용하여 숫자와 문자열을 구분하려면, C/C++ 코드에서 구분자(N: 또는 S:)를 활용하여 데이터를 구분하고, Oracle 프로시저에서 이를 처리하도록 할 수 있습니다. 여기서는 두 가지 주요 방법을 설명하겠습니다:
C/C++ 코드에서 데이터 전처리
Oracle 프로시저에서 데이터 처리
1. C/C++ 코드에서 데이터 전처리
C/C++에서는 입력 데이터를 N:과 S:로 구분하여 Oracle 프로시저로 전달할 수 있도록 준비합니다. 이를 위해 inData 배열을 처리하고, 각 값에 대해 N:은 숫자, S:는 문자열로 판단하여 Oracle 프로시저에 전달합니다.
위 코드에서 preprocessData 함수는 rawData 배열을 받아 각 값에 N: 또는 S:를 접두사로 추가하여 inData 배열에 저장합니다. 이렇게 하면 inData 배열은 숫자와 문자열을 구분할 수 있는 형식으로 변환됩니다.
2. Oracle 프로시저에서 데이터 처리
Oracle 프로시저에서는 전달된 데이터를 구분자(N: 또는 S:)에 따라 숫자와 문자열을 구분해서 처리할 수 있습니다. 이때 문자열의 앞 두 문자를 확인하여 숫자와 문자열을 판별하고, 그에 맞는 처리 로직을 수행합니다.
예제: Oracle 프로시저에서 구분자 처리
CREATE OR REPLACE PROCEDURE bulk_insert_proc ( p_data IN SYS.ODCIVARCHAR2LIST -- 문자열 배열 타입 ) IS v_prefix VARCHAR2(2); v_value VARCHAR2(4000); BEGIN FOR i IN 1..p_data.COUNT / 13 LOOP FOR j IN 1..13 LOOP v_prefix := SUBSTR(p_data((i-1)*13 + j), 1, 2); -- 앞의 구분자 확인 v_value := SUBSTR(p_data((i-1)*13 + j), 3); -- 구분자 이후의 값 IF v_prefix = 'N:' THEN -- 숫자 처리: 여기서는 예를 들어 숫자 컬럼에 값을 삽입 INSERT INTO EXTUREPLUSSTOCKFOREIGNERMASTER (number_column) VALUES (TO_NUMBER(v_value)); ELSIF v_prefix = 'S:' THEN -- 문자열 처리: 문자열 컬럼에 값을 삽입 INSERT INTO EXTUREPLUSSTOCKFOREIGNERMASTER (string_column) VALUES (v_value); END IF; END LOOP; END LOOP; COMMIT; END; /
프로시저 설명:
구분자 확인: SUBSTR 함수로 문자열의 처음 두 글자인 N: 또는 S:를 확인하여, 숫자인지 문자열인지를 구분합니다.
숫자 처리: N:으로 시작하는 값은 TO_NUMBER를 사용해 숫자로 변환하여 숫자 컬럼에 삽입합니다.
문자열 처리: S:로 시작하는 값은 그대로 문자열로 처리하여 문자열 컬럼에 삽입합니다.
3. C/C++에서 Oracle 프로시저 호출
C/C++ 코드에서 위와 같이 전처리된 inData 배열을 Oracle 프로시저로 전달할 수 있습니다. 이때 각 레코드는 13개의 값을 가지며, 각 값은 N: 또는 S:로 시작하는 형태로 전달됩니다.
예제: Oracle 프로시저 호출
#include <oci.h>
// OCI 핸들 및 환경 초기화 OCIEnv *env; OCIError *err; OCISvcCtx *svc; OCIStmt *stmt; OCIBind *bind; OCIArray *array_data;
구분자 방식("N:12345"와 "S:Hello World")을 적용하여 숫자와 문자열을 구분하려면, C/C++ 코드에서 구분자(N: 또는 S:)를 활용하여 데이터를 구분하고, Oracle 프로시저에서 이를 처리하도록 할 수 있습니다. 여기서는 두 가지 주요 방법을 설명하겠습니다:
C/C++ 코드에서 데이터 전처리
Oracle 프로시저에서 데이터 처리
1. C/C++ 코드에서 데이터 전처리
C/C++에서는 입력 데이터를 N:과 S:로 구분하여 Oracle 프로시저로 전달할 수 있도록 준비합니다. 이를 위해 inData 배열을 처리하고, 각 값에 대해 N:은 숫자, S:는 문자열로 판단하여 Oracle 프로시저에 전달합니다.
위 코드에서 preprocessData 함수는 rawData 배열을 받아 각 값에 N: 또는 S:를 접두사로 추가하여 inData 배열에 저장합니다. 이렇게 하면 inData 배열은 숫자와 문자열을 구분할 수 있는 형식으로 변환됩니다.
2. Oracle 프로시저에서 데이터 처리
Oracle 프로시저에서는 전달된 데이터를 구분자(N: 또는 S:)에 따라 숫자와 문자열을 구분해서 처리할 수 있습니다. 이때 문자열의 앞 두 문자를 확인하여 숫자와 문자열을 판별하고, 그에 맞는 처리 로직을 수행합니다.
예제: Oracle 프로시저에서 구분자 처리
CREATE OR REPLACE PROCEDURE bulk_insert_proc ( p_data IN SYS.ODCIVARCHAR2LIST -- 문자열 배열 타입 ) IS v_prefix VARCHAR2(2); v_value VARCHAR2(4000); BEGIN FOR i IN 1..p_data.COUNT / 13 LOOP FOR j IN 1..13 LOOP v_prefix := SUBSTR(p_data((i-1)*13 + j), 1, 2); -- 앞의 구분자 확인 v_value := SUBSTR(p_data((i-1)*13 + j), 3); -- 구분자 이후의 값 IF v_prefix = 'N:' THEN -- 숫자 처리: 여기서는 예를 들어 숫자 컬럼에 값을 삽입 INSERT INTO EXTUREPLUSSTOCKFOREIGNERMASTER (number_column) VALUES (TO_NUMBER(v_value)); ELSIF v_prefix = 'S:' THEN -- 문자열 처리: 문자열 컬럼에 값을 삽입 INSERT INTO EXTUREPLUSSTOCKFOREIGNERMASTER (string_column) VALUES (v_value); END IF; END LOOP; END LOOP; COMMIT; END; /
프로시저 설명:
구분자 확인: SUBSTR 함수로 문자열의 처음 두 글자인 N: 또는 S:를 확인하여, 숫자인지 문자열인지를 구분합니다.
숫자 처리: N:으로 시작하는 값은 TO_NUMBER를 사용해 숫자로 변환하여 숫자 컬럼에 삽입합니다.
문자열 처리: S:로 시작하는 값은 그대로 문자열로 처리하여 문자열 컬럼에 삽입합니다.
3. C/C++에서 Oracle 프로시저 호출
C/C++ 코드에서 위와 같이 전처리된 inData 배열을 Oracle 프로시저로 전달할 수 있습니다. 이때 각 레코드는 13개의 값을 가지며, 각 값은 N: 또는 S:로 시작하는 형태로 전달됩니다.
예제: Oracle 프로시저 호출
#include <oci.h>
// OCI 핸들 및 환경 초기화 OCIEnv *env; OCIError *err; OCISvcCtx *svc; OCIStmt *stmt; OCIBind *bind; OCIArray *array_data;
입력 데이터를 C/C++에서 Oracle로 전달하기 전에, 숫자와 문자열을 구분하는 구분자를 추가합니다. 예를 들어:
숫자는 "N:<value>" 형태
문자열은 "S:<value>" 형태
프로시저 수정
CREATE OR REPLACE PROCEDURE bulk_insert_proc ( p_data IN SYS.ODCIVARCHAR2LIST ) IS v_prefix VARCHAR2(1); v_value VARCHAR2(4000); BEGIN FOR i IN 1..p_data.COUNT LOOP v_prefix := SUBSTR(p_data(i), 1, 2); -- 앞의 구분자 확인 v_value := SUBSTR(p_data(i), 3); -- 구분자 이후의 값
IF v_prefix = 'N:' THEN INSERT INTO your_table (number_column, string_column) VALUES (TO_NUMBER(v_value), NULL); ELSIF v_prefix = 'S:' THEN INSERT INTO your_table (number_column, string_column) VALUES (NULL, v_value); END IF; END LOOP;