어떻게 python파일을 c#에서 실행시킬 수 있을까?
여러 방법이 있지만 이번에 소개할 내용은 [ic]Process()[/ic]를 이용한 방법이다.
1.예제 코드 준비 / 기본 컨셉
1) python코드
//test1.py
print('hello world\n hello world2\n hello world3' )
2) C# 코드
[ic]test1.py[/ic]를 c#에서 동작시켜 보겠다.
기본적으로 2가지 컨셉이 있다.
동작원리는 같지만 코드 형태가 조금 다르기 때문에 소개한다.
(1) [ic]Process()[/ic] 객체 생성방식
Process process = new Process();
[ic]Process[/ic] 객체를 생성한다.
// Set the file path of the Python executable
process.StartInfo.FileName = @"C:\Users\AppData\Local\Programs\Python\Python310\python.exe";
// Set the arguments for the Python script
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
[ic].StartInfo[/ic]를 통해 파이썬 명령어([ic].FileName[/ic])와 실행시킬 파일명([ic].Arguments[/ic])을 작성한다.
이때 python 실행 파일이 환경변수로 등록되어 있다면 python만 입력해도 무방하다.
process.StartInfo.FileName = @"python";
😀파이썬 파일을 실행할 때 [ic]'python 파일명'[/ic] 을 입력한다.
이는 환경변수로 등록되어 있었기 때문에 가능한 거다.
만약 등록되어 있지 않다면 파이썬 실행파일 full path를 작성해야 한다.
ex) "C:\Users\AppData\Local\Programs\Python\Python310\python.exe 파일명"
process.Start();
//output
/*
hello world
hello world2
hello world3
*/
[ic]process.Start()[/ic]를 통해 실행시켜 준다.
(2) [ic]ProcessStartInfo()[/ic] 객체 생성 방식
[ic]ProcessStartInfo()[/ic]객체 생성
ProcessStartInfo start = new ProcessStartInfo();
[ic]ProcessStartInfo[/ic] 객체에 있는 [ic]Filename[/ic], [ic]Arguments[/ic]값을 할당해 준다.
start.FileName = @"python";
start.Arguments = @"D:\pythonproject\detectionserver\test1.py";
여기서 차이점이 발생한다.
Process.Start(start);
[ic]Process.Start()[/ic] 인자로 [ic]ProcessStartInfo[/ic]객체를 넣어준다
지금까지는 python 출력값을 터미널창을 통해 확인해 봤다.
그 출력값을 c# 변수에 담아 사용할 순 없을까?
그때 등장하는 것이 [ic].RedirectStandardOutput[/ic]다.
2. [ic].RedirectStandardOutput[/ic] 사용법
출력 output을 리다이렉트 시키는 방법이다.
사용법은 간단한다.
[ic]process.StartInfo.RedirectStandardOutput = true;[/ic]로 설정해주면 된다.
// Set the file path of the Python executable
process.StartInfo.FileName = @"python";
// Set the arguments for the Python script
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
//Redirect the output of the process to the StandardOutput property
process.StartInfo.RedirectStandardOutput = true;
// Start the process
process.Start();
//output
/*
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp949'>
OSError: [Errno 22] Invalid argument
*/
하지만 이대로 실행하면 에러가 발생한다.
redirect 시킨다고 하였지만 목적 장소를 지정하지 않았기 때문이다.
[ic]process.StandardOutput.ReadToEnd()[/ic]통해 redirect값을 받을 변수를 세팅해 준다.
// Set the file path of the Python executable
process.StartInfo.FileName = @"python";
// Set the arguments for the Python script
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
//Redirect the output of the process to the StandardOutput property
process.StartInfo.RedirectStandardOutput = true;
// Start the process
process.Start();
// Read the output of the process from the StandardOutput property
string output = process.StandardOutput.ReadToEnd();
// Do something with the output
Console.WriteLine(output);
//output
/*
hello world
hello world2
hello world3
*/
참고)
.ReadToEnd ⇒ output 처음부터 끝까지 읽어서 다 담겠다
.ReadLine ⇒ output 한 줄만 담겠다.
// .ReadLine 적용시 output은 전체줄이 아닌 1줄만 읽는다.
hello world
/*
output이 있다면 input도 있지 않을까?
[ic]RedirectStandardInput[/ic]는 input값을 python코드로 주입할 때 사용된다.
3. [ic].RedirectStandardInput[/ic] 사용법
1) python코드
//test1.py
[ic]input()[/ic]함수를 통해 c#에서 넘어올 input값을 대기한다.
# Read input from the standard input stream
input_string = input()
# Process the input
print("You entered:", input_string)
2) c# 코드
[ic]process.StartInfo.RedirectStandardInput = true;[/ic] 설정한다.
process.StartInfo.FileName = @"python";
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.StandardInput.WriteLine("Hello world to python");
process.StandardInput.Flush();
process.StandardInput.Close();
//output
// You entered: Hello world to python1
process.StandardInput.WriteLine | input으로 넣을 값을 작성한다. |
process.StandardInput.Flush() | input으로 넣은 값은 일시적으로 buffer에 저장된다. 이 buffer에 저장된 값을 python input값으로 (확실하게) 넘겨주는 역할을 하는 것이 Flush()다. |
process.StandardInput.Close() | input 작업을 마친다고 알려주는 코드다. |
실수 주의😭
[ic]process.Start()[/ic] 위치를 잘 기억하자. 제일 뒤에 오면 오류가 발생한다.
intput값으로 두 개 이상을 넣고 싶다면 어떻게 할까?
4. input으로 두개 이상 넣기
//c# 코드
process.StartInfo.FileName = @"python";
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.StandardInput.WriteLine("Hello world to python1");
process.StandardInput.WriteLine("Hello world to python2");
process.StandardInput.Close();
[ic].WriteLine[/ic]를 두 개 이상 작성하면 된다
//python 코드
# Read input from the standard input stream
lines = []
while True:
try:
line = input()
lines.append(line)
except EOFError:
break
# Process the input
print("You entered:")
for line in lines:
print(line)
다만 input()을 여러 번 받아야 하므로 파이썬 코드 수정이 필요하다.
그런데 좀 번거롭다.
그래서 다른 방식을 소개한다.
//c# 코드
process.StartInfo.FileName = @"python";
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py ""Hello world to python1"" ""Hello world to python2"" ";
process.Start();
[ic]RedirectStandardInput[/ic] 를 지운다.
그리고 [ic].Arguments[/ic]에 input으로 사용할 값을 추가해 준다.
""는 각 인자별로 구분해주기 용도다.
안 넣어주면 space마다 input으로 인식을 해버린다.
예를 들어 'Hello world to python1' 를 넣으면 Hello, world, to, python1과 같이 input을 4개로 인식한다.
c# 코드 변경에 따라 python 코드 변경도 필요하다.
import sys
print(sys.argv)
arg1, arg2 = sys.argv[1], sys.argv[2]
#ouput
'''
["D:\pythonproject\detectionserver\test1.py","Hello world to python1,"Hello world to python2"]
'''
[ic]sys.argv[/ic]는 [ic]process.StartInfo.Arguments[/ic]에 담긴 값을 리스트형태로 가지고 있다.
이 중 0번째 값은 파이썬 파일 실행경로이고 1, 2번째가 input값이다.
5) [ic]process.WaitforExit();[/ic]
[ic]process.WaitforExit();[/ic] 는 이전 process 작업이 완전히 끝날 때까지 기다려주는 함수다.
process.StartInfo.FileName = @"C:\Users\AppData\Local\Programs\Python\Python310\python.exe";
// Set the arguments for the Python script
process.StartInfo.Arguments = @"D:\pythonproject\detectionserver\test1.py";
//Redirect the output of the process to the StandardOutput property
process.StartInfo.RedirectStandardOutput = true;
// Start the process
process.Start();
//////////////////////////////////////////////////////////////////////////////////
///////////////// 위 작업이 끝날때까지 기다리기 /////////////////////////////////
process.WaitForExit();
//////////////////////////////////////////////////////////////////////////
// Read the output of the process from the StandardOutput property
string output = process.StandardOutput.ReadToEnd();
// Do something with the output
Console.WriteLine(output);
시간이 오래 걸리는 작업일 경우 기다리지 않고 output을 받으려고 하면 오류가 발생한다.
이때 [ic]process.WaitforExit();[/ic] 는 유용한 함수다.
FAQ)
Q) 파이썬 파일을 가상환경 상태에서 실행하고 싶다면?
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.StandardInput.WriteLine(@"D:\pythonproject\detectionserver\venv\Scripts\activate.bat");
process.StandardInput.WriteLine(@$"python D:\pythonproject\detectionserver\test1.py");
process.StandardInput.Flush();
process.StandardInput.Close();
이때는 다이렉트로 파일을 실행시키기보다 cmd를 통한 방법이 좋다.
원리는 같다. cmd창을 열고 input값을 통해 값을 입력하면 된다.
참고로 'D:\pythonproject\detectionserver\venv\Scripts\activate.bat' 은 가상환경 실행파일의 절대경로다.
Q) 터미널 창이 뜨는게 보기싫다. 끄고 싶다면?
[ic]process.StartInfo.CreateNoWindow[/ic]를 true로 설정하면된다.
process.StartInfo.CreateNoWindow = true;
'c#' 카테고리의 다른 글
[c# EntityFramework] dbcontext 마이그레이션 롤백하는 방법 (0) | 2023.02.28 |
---|---|
[c#] json 파싱하는법 (0) | 2023.02.23 |
[c#] Entity Framework 사용 방법(code-first) (0) | 2022.08.19 |
[c#] 의존성 주입(dependency Injection) 이란? (2) | 2022.08.10 |
[c#] Insert, Update, Delete 하는법 with EntityFramework (0) | 2022.07.21 |
댓글