I'm using a thread to run one function of my code, here's a snippet:
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = []
for addresses in ipa_str_s:
futures.append(executor.submit(checking_connection, ip_address=addresses))
for future in concurrent.futures.as_completed(futures):
save_result = (future.result())
saving_statistics(save_result, saving)
the variable ipa_str_s
has a list of IP addresses.
the saving_statistics
function, which waits for each call of the checking_connection
function to give me the opportunity to save the result
.
Called function saving_statistics
:
def saving_statistics(save_result, saving):
with open(saving, 'a', encoding='utf-8') as csv_file:
csv_writer = csv.writer(csv_file, delimiter=';')
csv_writer.writerow(['IP-address', 'Packets_transmitted', 'Packets_received'])
csv_writer.writerow(save_result)
if specify the mode a
, then get this result:
IP-address;Packets_transmitted;Packets_received
192.168.1.1;3;3
IP-address;Packets_transmitted;Packets_received;
192.168.1.2;3;0
IP-address;Packets_transmitted;Packets_received;
192.168.1.3;3;0
if specify the mode w
, then get this result:
IP-address;Packets_transmitted;Packets_received
192.168.1.3;3;0
Could you tell me please, how can I come to the normal content of a file like this:
IP-address;Packets_transmitted;Packets_received
192.168.1.1;3;3
192.168.1.2;3;0
192.168.1.3;3;0
Thank you very much!
CodePudding user response:
Your function writes the first line (IP-address;Packets_transmitted;Packets_recieved) every time the function saving_statistics gets called.
I see three solutions:
- Open the file elsewhere and write the first line, then call the function as needed. Close the file when the program terminates.
- Have a variable that is True when the function is first called, and then have it changed to false. Use this to determine whether or not to print the header line
- Save the ip addresses in a list object, and write all of them when the program terminates.
Depending on how long you want it to run changes the best option. If you plan for it to run a while, I would do 1 and have a file.close() at the end of your main(), or however you are running this. If it is a short number of items, 3 may be the easiest. 2 will result in the least amount of code change.
CodePudding user response:
FWIW, in most cases, CSV files should not be appended to: they should be written from top-to-bottom once. Log files are a good candidate for appending.
But enough of my philosophy.
You'll at least need to check in saving_statistics
to see if the file exists, and if it doesn't add the header and write the row you have. If it does exist you can then go ahead and append:
import csv
from os.path import exists
def saving_statistics_append(save_result, saving):
csv_writer = None
if not exists(saving):
csv_file = open(saving, "w", newline="")
csv_writer = csv.writer(csv_file, delimiter=";")
csv_writer.writerow(["IP-address", "Packets_transmitted", "Packets_received"])
else:
csv_file = open(saving, "a", encoding="utf-8")
csv_writer = csv.writer(csv_file, delimiter=";")
csv_writer.writerow(save_result)
csv_file.close()
Here's how'd I do this, without append:
def saving_statistics_refresh(save_result, saving):
prev_rows = []
if exists(saving):
with open(saving, newline="") as f:
reader = csv.reader(f, delimiter=";")
next(reader) # discard prev header
prev_rows = list(reader)
with open(saving, "w", newline="") as f:
writer = csv.writer(f, delimiter=";")
writer.writerow(["IP-address", "Packets_transmitted", "Packets_received"])
writer.writerows(prev_rows)
writer.writerow(save_result)
Calling either of those repeatedly with:
saving_statistics_append(["127.0.0.0", 0, 10], "data.csv")
saving_statistics_append(["127.0.0.0", 1110, 99], "data.csv")
saving_statistics_refresh(["127.0.0.0", 333, 444], "data.csv")
saving_statistics_refresh(["127.0.0.0", 77777, 88888], "data.csv")
I get:
IP-address;Packets_transmitted;Packets_received
127.0.0.0;0;10
127.0.0.0;1110;99
127.0.0.0;333;444
127.0.0.0;77777;88888
You can use the DictReader/Writer to help enforce the structure of the CSV:
from collections import namedtuple
Packet_log = namedtuple(
"Packet_log",
["IP_address", "Packets_transmitted", "Packets_received"],
)
def saving_statistics_dict(save_result: Packet_log, saving):
prev_rows = []
if exists(saving):
with open(saving, newline="") as f:
reader = csv.DictReader(f, delimiter=";")
prev_rows = list(reader)
with open(saving, "w", newline="") as f:
writer = csv.DictWriter(f, delimiter=";", fieldnames=Packet_log._fields)
writer.writeheader()
writer.writerows(prev_rows)
writer.writerow(save_result._asdict())
saving_statistics_append(["127.0.0.0", 0, 10], "data.csv")
saving_statistics_append(["127.0.0.0", 1110, 99], "data.csv")
saving_statistics_dict(Packet_log("127.0.0.0", 333, 444), "data.csv")
saving_statistics_dict(Packet_log("127.0.0.0", 77777, 88888), "data.csv")