Tạo file CSV lưu dữ liệu dựa trên thời gian

Chào mọi người, mình đang cần lưu dữ liệu cảm biến từ 12 kênh vào file csv bằng C++. Mình đã lưu dữ liệu ổn rồi, nhưng trước kia là nếu mình muốn ngừng đọc và lưu dữ liệu thì phải tắt file exe đi. Giờ họ yêu cầu là máy tính phải chạy cả tháng, không cần tắt chương trình mà vẫn tự động tạo ra file csv mới sau 1 khoảng thời gian giả dụ 1 tiếng. Vì nếu lưu toàn bộ dữ liệu cả tháng vào 1 file csv duy nhất thì dung lượng lớn quá có lẽ không mở được. Các file có thể tạo ra như: 20190516_10h0m0s, 20190516_11h0m0s…

Để làm điều đó mình đã dùng cấu trúc struct tm và hàm for để sau khi số phút lên tới 60’ sẽ đóng file đầu tiên và file thứ 2 tự động được tạo. Ban đầu mình đặt file.open trong vòng lặp for, nhưng mỗi vòng lặp thì các dòng hiển thị Ngày, giờ, số kênh đều ghi lại vào file rất chuối nên mình để file.open ngoài vòng lặp. Nhưng sau đó thì dữ liệu lưu đúng mà lại không tự động tạo file mới sau 1 tiếng như mình muốn.
Dưới đây là code của mình. Mong mọi người chỉ cách khắc phục và ra kết quả như ý.

void EX_GetMultiValue(LONG i_lDriverHandle,WORD i_wSlotID,struct SlotInfo &i_SlotInfo)
{
     char filename[20], filename2[20];
      time_t rawtime;
      struct tm * timeinfo; 
      time(&rawtime);
      timeinfo = localtime(&rawtime);
      timeinfo->tm_mon++;								// Because the range of tm_mon is 0~11, so we need to increment it by 1
      timeinfo->tm_year = timeinfo->tm_year + 1900;		// Because year counted since 1900

      clock_t start = clock ();
    sprintf(filename, "%04d%02d%02d_%02dh%02dm%02ds.csv", 
              timeinfo->tm_year, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec );
      printf("\nFilename: %s", filename);

      ofstream dest2;
      dest2.open(filename, ios_base::app | ios_base::out);
      dest2<<"Date"<<","<<"Time"<<","<<"milisecond"<<","<<"Channel 0"<<","<<"Channel 1" << ","<<"Channel 2"<< ","<<"Channel 3"<< ","<<"Channel 4"<< ","<<"Channel 5"<< ","<<"Channel 6"<< ","<<"Channel 7"<< ","<<"Channel 8"<< ","<<"Channel 9"<< ","<<"Channel 10"<< ","<<"Channel 11"<<","<<endl;

    	for(;timeinfo->tm_min < 60;)
      { 

      ofstream dest;
      dest.open(filename, ios_base::app | ios_base::out);

    	LONG lGetMultiValueResult = AIO_GetValues(i_lDriverHandle, i_wSlotID, wRawValue); //get raw value
    	if (ERR_SUCCESS == lGetMultiValueResult)
    	{				
    				clock_t timeElapsed =  clock() - start;
    				unsigned secElapsed = timeElapsed / CLOCKS_PER_SEC;
    				unsigned msElapsed = timeElapsed / CLOCKS_PER_MS;

    		while(msElapsed >= 1000)
    			msElapsed -= 1000;
    		while((timeinfo->tm_sec+secElapsed) > 59)
    		{
    			timeinfo->tm_sec -= 60;	
    			timeinfo->tm_min++;
    		}
    		while(timeinfo->tm_min > 59)
    		{	
    			timeinfo->tm_min -= 60;
    			timeinfo->tm_hour++;
    		}
    		while(timeinfo->tm_hour > 23)
    		{
    			timeinfo->tm_hour -= 24;			
    			timeinfo->tm_mday++;
    		}


    		
    		dest<<timeinfo->tm_year<<"-"<< timeinfo->tm_mon<<"-"<< timeinfo->tm_mday<< ","<< timeinfo->tm_hour<<"h"<<timeinfo->tm_min<<"m"<<timeinfo->tm_sec+secElapsed<<"s"<<",";	
    		dest<<msElapsed<<"ms"<<",";
    		for (iCnt = 0; iCnt < g_ChannelNum ; iCnt++)
    		{
    			wRangeType = *(i_SlotInfo.wChRange + iCnt); //get range type
    			EX_ScaleRawValue(wRangeType,wRawValue[iCnt], &dScaledValue, cUnit);//get scale value			
    			if (strcmp(cUnit,"UN") != 0)
    			{
    				printf("Channel %d raw data is 0x%04X, scaled value is %.4f %s.\n", iCnt, wRawValue[iCnt], dScaledValue,cUnit);	
    				dest<< dScaledValue <<",";
    	
    				Sleep(1);
    			}
    			else
    				printf("Channel %d range is unknown.\n", iCnt);
    		}
    		dest<<endl;
    	}
    	else
    		printf("Fail to get value, error code = %d\n", lGetMultiValueResult);
    	dest.close();
    	dest2.close();
    	
    	if (dest == NULL)
    	{
    		perror("Error creating file: ");
    		return;
    	}
}

Hi Long Hưng.

  1. Mình góp ý một số chỗ về thuật toán:
    while(msElapsed >= 1000) msElapsed -= 1000;
    có thể thay bằng phép chia lấy dư. Tượng tự phía dưới kết hợp chia lấy dư và nghuyên.
  2. Về thuật toán để ghi file theo thời gian thì cái này dễ. Tạo một class Store mỗi khi đẩy một struct vào thì kiểm tra thời gian. Nếu quá thì lưu file cũ tạo file mới, gán lại biến file rồi chạy tiếp như lưu file thông thường.
    P/S Cách này cài đặt đơn giản nhưng có nhược điểm là thời điểm ghi file phụ thuộc vào tần suất ghi dữ liệu. Muốn lưu định kì không phụ thuộc vào tần suất lưu dữ liệu thì bạn cần một timer.
2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?