Lief Inviato 7 Luglio 2017 Segnala Condividi Inviato 7 Luglio 2017 Ieri notte ero particolarmente creativo e ho ricevuto l'illuminazione per la creazione di un piccolo programma che rinomina i file in batch in modo progressivo (esempio prendo 10 file li rinomina da 000 a 009). Ma quale linguaggio usare? Ho pensato subito al C perchè è ottimo per prototipizzare sui file (è un linguaggio molto semplice che, senza librerie aggiuntive, consente di usare semplici system call come rename o chiamare la bash con system), anche se successivamente mi sono quasi pentito della scelta (visto e considerato come si lavora male sulle stringhe). Dopo averlo creato (come vedete molto velocemente, usando addirittura un goto per puro sfizio di farlo): Spoiler // // main.c // RinominaFast // // Created by LiefLayer on 06/07/17. // Copyright © 2017 LiefLayer. All rights reserved. // #include <stdio.h> #include <string.h> #include <unistd.h> int main(int argc, const char * argv[]) { char stringa[256]; char stringaFinal[256][256]; int ret = -1; char oldname[256][256]; char oldnameWithEstension[256][256]; char path[256]; int index = 0; char myInt[3]; char myEstension[5]; int numElem = 0; //immetto i nomi dei file da rinominare start: printf("Immetti il nome del file attuale con l'estensione, digitare stop per fermarsi!\n"); if (fgets(oldname[index], sizeof(oldname[index]), stdin)) { if (oldname[index][strlen(oldname[index]) - 1] == '\n') { oldname[index][strlen(oldname[index]) -1] = '\0'; } if(strcmp(oldname[index], "stop") != 0){ index++; goto start; }else{ oldname[index][0] = '\0'; index--; numElem = index; } }else { printf("Errore 00: nome attuale troppo lungo\n"); } index = 0; //immetto il path dei file da rinominare printf("Immetti il path del file attuale!\n"); if (fgets(path, sizeof(path), stdin)) { if (path[strlen(path) - 1] == '\n') { path[strlen(path) -1] = '\0'; } }else { printf("Errore 02: path troppo lungo\n"); } while(index <= numElem){ strcat(stringaFinal[index], path); index++; } index = 0; //prendo il nuovo nome del file printf("Immetti il nome principale!\n"); if (fgets(stringa, sizeof(stringa), stdin)) { if (stringa[strlen(stringa) - 1] == '\n') { stringa[strlen(stringa) -1] = '\0'; } }else { printf("Errore 01: nome troppo lungo\n"); } while(index <= numElem){ strcat(stringaFinal[index], stringa); index++; } index = 0; while(index <= numElem){ //imposto l'index da intero a stringa sprintf(myInt, "%d", index); if(index > 9){ strcat(stringaFinal[index], "0"); }else{ strcat(stringaFinal[index], "00"); } //lo metto nel mio nome finale insieme al giusto numero di zeri strcat(stringaFinal[index], myInt); index++; } index = 0; //aggiungo l'estensione printf("Immetti l'estensione!\n"); if (fgets(myEstension, sizeof(myEstension), stdin)) { if (myEstension[strlen(myEstension) - 1] == '\n') { myEstension[strlen(myEstension) -1] = '\0'; } }else { printf("Errore 03: estensione errata\n"); } while(index <= numElem){ strcat(stringaFinal[index], myEstension); index++; } index = 0; while (index <= numElem) { strcat(oldnameWithEstension[index], path); strcat(oldnameWithEstension[index], oldname[index]); //rinomino il mio vecchio file con il nuovo nome compreso di estensione ret = rename(oldnameWithEstension[index], stringaFinal[index]); if(ret == 0){ printf("Successo File %d %s %s %s!\n", index, oldname[index], oldnameWithEstension[index], stringaFinal[index]); }else{ printf("Fallimento File %d!\n", index); } index++; } printf("Fine!\n"); return 0; } Ho pensato che fosse un'ottima scusa per provare a utilizzare tale codice dentro un'applicazione con solo l'interfaccia grafica scritta in Swift. Per farlo ho trovato molto più rapido incapsulare il mio codice C dentro una classe Objective-C (è stato così molto più semplice passare le stringhe come parametri): Spoiler // // Core.m // RinominaFast // // Created by LiefLayer on 06/07/17. // Copyright © 2017 LiefLayer. All rights reserved. // #import <Foundation/Foundation.h> #include <stdio.h> #include <string.h> #include <unistd.h> #import "Core.h" @implementation Core char stringa[10000]; char stringaFinal[10000][10000]; char oldname[10000][10000]; char oldnameWithEstension[10000][10000]; char path[10000]; int myIndex = 0; char myInt[10000]; char myEstension[1000]; int numElem = 0; char commando[10000]; //immetto i nomi dei file da rinominare - (int) coreProgramPart1 : (NSString *) daRinominare{ strcpy(oldname[myIndex], [daRinominare UTF8String]); if (oldname[myIndex][strlen(oldname[myIndex]) - 1] == '\n') { oldname[myIndex][strlen(oldname[myIndex]) -1] = '\0'; } if(strcmp(oldname[myIndex], "stop") != 0){ myIndex++; return 1; }else{ oldname[myIndex][0] = '\0'; myIndex--; numElem = myIndex; } myIndex = 0; return 0; } - (void) coreProgramPart0 : (NSString *) daRinominare{ strcpy(path, [daRinominare UTF8String]); if (path[strlen(path) - 1] == '\n') { path[strlen(path) -1] = '\0'; } while(myIndex <= numElem){ strcpy(stringaFinal[myIndex], ""); strcat(stringaFinal[myIndex], path); myIndex++; } myIndex = 0; } - (void) coreProgramPart2 : (NSString *) daRinominare{ strcpy(stringa, [daRinominare UTF8String]); if (stringa[strlen(stringa) - 1] == '\n') { stringa[strlen(stringa) -1] = '\0'; } while(myIndex <= numElem){ strcat(stringaFinal[myIndex], stringa); myIndex++; } myIndex = 0; } - (void) coreProgram { while(myIndex <= numElem){ //imposto l'index da intero a stringa sprintf(myInt, "%d", myIndex); if(myIndex > 9 && myIndex <= 99){ strcat(stringaFinal[myIndex], "0"); }else if(myIndex > 99){ strcat(stringaFinal[myIndex], ""); }else{ strcat(stringaFinal[myIndex], "00"); } //lo metto nel mio nome finale insieme al giusto numero di zeri strcat(stringaFinal[myIndex], myInt); myIndex++; } myIndex = 0; } - (void) coreProgramPart3 : (NSString *) daRinominare{ strcpy(myEstension, [daRinominare UTF8String]); //aggiungo l'estensione if (myEstension[strlen(myEstension) - 1] == '\n') { myEstension[strlen(myEstension) -1] = '\0'; } while(myIndex <= numElem){ strcat(stringaFinal[myIndex], myEstension); myIndex++; } myIndex = 0; //costruisce e passa il comando da eseguire su bash while (myIndex <= numElem) { strcat(oldnameWithEstension[myIndex], path); strcat(oldnameWithEstension[myIndex], oldname[myIndex]); //rinomino il mio vecchio file con il nuovo nome compreso di estensione int ret = rename(oldnameWithEstension[myIndex], stringaFinal[myIndex]); if(ret == 0){ printf("Successo File %d \n", myIndex); }else{ printf("Fallimento File %d \n", myIndex); } myIndex++; } myIndex = 0; while (myIndex <= numElem) { strcpy(oldnameWithEstension[myIndex], ""); strcpy(stringaFinal[myIndex], ""); strcpy(oldname[myIndex], ""); myIndex++; } myIndex = 0; printf("Fine!\n"); } @end Ovviamente questo è il codice finale, in mezzo ci sono stati tanti passaggi. Ho così creato il .h per questa classe Spoiler // // Core.h // RinominaFast // // Created by LiefLayer on 06/07/17. // Copyright © 2017 LiefLayer. All rights reserved. // #ifndef Core_h #define Core_h #import <Foundation/Foundation.h> @interface Core : NSObject - (int) coreProgramPart1: (NSString *) daRinominare; - (void) coreProgramPart0: (NSString *) daRinominare; - (void) coreProgramPart2: (NSString *) daRinominare; - (void) coreProgram; - (void) coreProgramPart3: (NSString *) daRinominare; @end #endif /* Core_h */ e come si può vedere non ho dovuto modificare praticamente nulla del mio codice C vero e proprio. Ho dovuto infatti solo aggiungere il wrapper della classe e dei metodi Objective-C. Ovviamente ho dovuto anche creare un piccolo file bridge NomeProgetto-Bridging-Header.h dove ho solo scritto #import "Core.h" Successivamente ho poi modificato il codice per adattarsi alla mia interfaccia grafica scritta in Swift (che ovviamente prevede la selezione dei file attraverso una finestra di selezione dei file): Spoiler // // ViewController.swift // RinominaFast // // Created by LiefLayer on 06/07/17. // Copyright © 2017 LiefLayer. All rights reserved. // import Cocoa class ViewController: NSViewController { var instanceOfCore: Core = Core() var retPart1: Int = -1 var daRinominare: String! = ""; @IBOutlet var stringInInput: NSTextField! @IBOutlet var filename_field: NSTextField! var path = "" override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override var representedObject: Any? { didSet { // Update the view, if already loaded. } } @IBAction func browseFile(_ sender: Any) { let dialog = NSOpenPanel(); dialog.title = "Choose files"; dialog.showsResizeIndicator = true; dialog.showsHiddenFiles = false; dialog.canChooseDirectories = true; dialog.canCreateDirectories = true; dialog.allowsMultipleSelection = true; if (dialog.runModal() == NSModalResponseOK) { let result = dialog.urls // Pathname of the file var pathMyFile = "" var toIndex = 0; path = "" filename_field.stringValue = "" while(toIndex < result.count){ path = result[toIndex].path filename_field.stringValue = filename_field.stringValue + path + "'" let myUrl = URL(fileURLWithPath: path) let dirUrl = myUrl.deletingLastPathComponent() pathMyFile = dirUrl.path + "/" path = result[toIndex].lastPathComponent retPart1 = Int(instanceOfCore.coreProgramPart1(path)); path = result[toIndex].pathExtension toIndex += 1; } retPart1 = Int(instanceOfCore.coreProgramPart1("stop")); instanceOfCore.coreProgramPart0(pathMyFile) } else { // User clicked on "Cancel" return } } @IBAction func launchPart2(_ sender: Any) { if(retPart1 != 0){ return; } daRinominare = stringInInput.stringValue instanceOfCore.coreProgramPart2(daRinominare) instanceOfCore.coreProgram(); instanceOfCore.coreProgramPart3("."+path) } } Ovviamente il programma non è per nulla ottimizzato e potrebbe avere dei bug (non mi prendo responsabilità in caso perdiate dei dati, quindi non utilizzate questo programma su dati importanti). Però l'obbiettivo primario è stato raggiunto. Il programma è attualmente una sorta di MVC in cui la View (l'interfaccia grafica) è scritta in Swift e non ha alcuna funzionalità se non quella di passare l'input al Model (la classe C wrappata all'interno dell'Objective-C) attraverso il Controller (il bridge). Tutte le funzionalità di base sono svolte backend dal codice C originale, solo l'interfaccia grafica è in Swift. Questo mini-tutorial si conclude qui, spero che sia stato utile a qualcuno. Se volete più informazioni vi consiglio questo link stackoverflow: Spoiler https://stackoverflow.com/questions/32541268/can-i-have-swift-objective-c-c-and-c-files-in-the-same-xcode-project/32546879#32546879 Concludo dicendo solo che per usare le funzioni C in Swift direttamente (senza Objective-C) si può fare in questo modo: funzione_c("World".cStringUsingEncoding(NSUTF8StringEncoding)) lo scrivo perchè in linea di massima è l'unica cosa non proprio intuitiva ("come usare un oggetto C se in C gli oggetti non esistono? Semplice ne hanno creato uno"). Il vantaggio principale è ovviamente che se avete del codice C, C++ o Objective-C già scritto.... Oppure vi piace scrivere in linguaggi diversi. Potete farlo. In linea di massima potreste persino non saper scrivere codice Swift (e la costruzione dell'interfaccia grafica è particolarmente semplice). Link al commento Condividi su altri siti Altre opzioni di condivisione...
Messaggi raccomandati
Archiviato
Questa discussione è archiviata e chiusa a future risposte.