Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Mein Programm möchte Dateien verschieben. Da ich zum weiter testen schnell eine Grundfunktionalität brauche, möchte ich erstmal auf rename() zurückgreifen. Das Problem dabei ist, das dies nur innerhalb desselben Dateisystems geht. Die Frage ist, wenn ich das vorher prüfen möchte, ob es da ausreichend ist, für das Zielverzeichnis die Funktion
stat( name, &st );
aufzurufen und dann davon den Wert "st_dev" zu vergleichen. Das scheint zwar zu funktionieren, aber ich habe nirgends wirklich eine Angabe gefunden, was dieser Wert wirklich enthält. Ich habe einfach mal gepokert. Der Wert hat zwar mit Geräten und Partitionen zu tun, aber ist das wirklich ausreichend? Bisher habe ich da folgende Werte bekommen:
0x801
0x802
0x821
Ich möchte nicht den Fehlercode von rename() dafür auswerten müssen, da der ja auch andere Ursachen haben könnte.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Dakuan schrieb: und dann davon den Wert "st_dev" zu vergleichen. Das scheint zwar zu funktionieren, aber ich habe nirgends wirklich eine Angabe gefunden, was dieser Wert wirklich enthält.
Laut https://www.gnu.org/software/libc/manual/html_node/Attribute-Meanings.html
sagt dir das zur Laufzeit, auf welchem Gerät (bzw. Dateisystem) die Dateien liegen:
dev_t st_dev
Identifies the device containing the file. The st_ino and st_dev, taken together, uniquely identify the file. The st_dev value is not necessarily consistent across reboots or system crashes, however.
Ich möchte nicht den Fehlercode von rename() dafür auswerten müssen, da der ja auch andere Ursachen haben könnte.
Ein EXDEV Fehler (vgl. http://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html und man 3 errno) müsste da eigentlich ziemlich eindeutig sein:
[EXDEV]
The links named by new and old are on different file systems and the implementation does not support links between file systems.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Dann sollte ich wohl doch lieber rename() die Überprüfung überlassen, bevor ich einen (noch zu implementierenden) zweiten Versuch mit eigener Funktion starte. Mit UnionFS hatte ich bisher bewusst noch nichts zu tun (außer beim Experimentieren mit Live CDs). Zu etwa 95% wird mein Programm auf eine externe USB-Platte losgelassen. Inwieweit UnionFS bei meiner Anwendung sinnvoll ist, kann ich momentan nicht überblicken. Man will ja keine Dateien auf ein System verschieben, das beim nächsten Reboot nicht mehr existiert. Ist aber auch zu blöd, dass es keine echte Systemfunktion file_move() gibt, die einem diese Arbeit ab nimmt. Ich glaube, da haben es die Windowianer besser.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Ein Verschieben über Dateisystemgrenzen hinweg ist ja nichts anderes als ein Kopieren mit anschließendem Löschen des Originals (wenn der Kopiervorgang erfolgreich war).
Das ist mir im Prinzip bekannt, aber nachdem ich gelesen hatte, was dabei alles zu berücksichtigen ist (Zeitstempel, Attribute ...), wollte ich erstmal eine Abkürzung nehmen. Wobei ich aber auch nicht das Risiko eines Datenverlustes riskieren will. Was ich will, gehört ja fast schon in die Kategorie Dateimanager oder Bilderverwaltung. Von daher könnte ich natürlich die üblichen Verdächtigen benutzen. Aber leider bestehen alle aktuellen Programme auf "numerischer" Sortierung, was sich nicht mit meiner Namensgebung, die noch von Windows kommt, verträgt. Nur das leider nicht mehr aktuelle GQview sortierte so, wie ich es möchte. Dabei kann Linux das, wenn man die Option "alphasort" verwendet. Ich müsste da aber ca. 20.000 Dateien manuell umbenennen um das Problem zu beseitigen. Und "manuell" ist immer doof. Daher mein Versuch, hier in einem begrenzten Ausmaß korrigierend einzugreifen. Aber Danke für den Link zu mv. Daraus kann ich bestimmt noch viel lernen. Warum erweisen sich viele Projekte, die ich anfasse, als eine Nummer zu groß oder zu kompliziert 😢
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4563
Wohnort: Berlin
|
@Dakuan:
Warum erweisen sich viele Projekte, die ich anfasse, als eine Nummer zu groß oder zu kompliziert 😢
Weil Du C und C++ verwendest‽ SCNR 😈 Es gibt doch schon unzählige Umbenennungswerkzeuge — kann davon wirklich keines das was Du brauchst/willst? Falls nicht, wäre es nicht einfacher eines davon zu erweitern oder anzupassen, statt von Null selbst zu schreiben? Und wenn das hauptsächlich für Deine Sammlung von 20.000 Dateien ist, kann man da nicht einfacher und schneller speziell dafür ein paar Zeilen in einer ”Scriptsprache” (Perl, Python, Ruby, …) schreiben?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Dakuan schrieb: Das ist mir im Prinzip bekannt, aber nachdem ich gelesen hatte, was dabei alles zu berücksichtigen ist (Zeitstempel, Attribute ...), wollte ich erstmal eine Abkürzung nehmen. Wobei ich aber auch nicht das Risiko eines Datenverlustes riskieren will.
Wenn es hübsch-hässlich sein darf, könnte man mv mit system aufrufen 😇
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Weil Du C und C++ verwendest‽
Wenn ich eine Sammlung gut ausgetesteter C Funktionen habe, schreibe ich die nicht ohne zwingenden Grund neu. Besonders dann, wenn ich auch noch C Programme habe, die diese Funktion nutzen. Aber hier habe ich C angegeben, weil rename() ja eigentlich eine C Funktion ist. Was die Sache immer kompliziert macht, ist die Tatsache, dass ich zu wenig über das Innenleben von Linux weiß. Und das Umbenennen wäre nicht das Problem, aber die Dateien müssen erstmal gesucht und deren Zugehörigkeit zu einer Gruppe anderer Dateien überprüft werden.
Wenn es hübsch-hässlich sein darf, könnte man mv mit system aufrufen
Den Vorschlag habe ich bei StackOverflow auch schon gesehen.
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4563
Wohnort: Berlin
|
@Dakuan: Ich weiss nicht ob der Punkt richtig rüber kam: Das ist nicht eine Nummer zu gross und kompliziert weil Du C und C++ zusammen verwendest oder C-Funktionen in einem C++-Programm, sondern weil Du überhaupt diese beiden Sprachen verwendest. Und C++ anscheinend auch nicht in einer modernen Form und mit entsprechenden Bibliotheken/Rahmenwerken die einem das Leben einfacher und unkomplizierter machen. IMHO würde ein Wechsel von C + C++ + FLTK zu weniger C + modernes C++ + Qt schon einen sehr grossen Unterschied machen. Bei der FLTK-API würde heute glaube ich kein C++-Programmierer mehr sagen das sei C++. Die API ist voll von Arrays und Zeigern auf Arrays statt ordentlichen Containerobjekten und char* statt Zeichenkettenobjekten. Die STL-Datentypen werden da soweit ich das sehe überhaupt nicht verwendet, und FLTK bietet auch keine eigenen Container als Ersatz. Ich persönlich würde mich mit der Komplexität von C++ ja auch schon nicht mehr herumschlagen wollen wenn es dafür keinen guten Grund gibt. Was für mich eigentlich nur tatsächlich benötigte rohe CPU-Geschwindigkeit und/oder volle Kontrolle über die Speicherverwaltung wäre. Beides sehe ich bei einem Umbenennungswerkzeug nicht. Das kann man auch in C#, Java, Kotlin, … schreiben und von deren Ausdrucksstärke und den Bibliotheken und Möglichkeiten der IDEs profitieren, oder in Perl, Python, Ruby, … wo man sich noch ein bisschen mehr Ausdrucksstärke durch dynamische Typisierung “erkauft“. Aber man kommt halt mit allem schneller voran als mit C + C++ + FLTK.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Zu Qt: Ich denke, es hat wenig mit C++ zu tun, wenn man erst ein Zusatzprogramm laufen lassen muss, um C++ Quelltext zu bekommen.
(FLTK:) Die STL-Datentypen werden da soweit ich das sehe überhaupt nicht verwendet, und FLTK bietet auch keine eigenen Container als Ersatz.
Das hat wohl mit der Absicht zu tun, keine zusätzlichen Abhängigkeiten zu erzeugen. Das verhindert aber nicht, das man diese doch verwendet.
... Beides sehe ich bei einem Umbenennungswerkzeug nicht.
Ich glaube da ist in meinem Bemühen, mich kurz zu fassen, einiges zu kurz gekommen. Das reine (nur) Umbenennen ist hier nicht das Problem. Deshalb jetzt die Langfassung: Ich sehe das als Programmierübung und bin von diesem Beispielprogramm ausgegangen und habe das etwas verfeinert. Danach habe ich dann angefangen eine Anwendung für diese Funktionalität zu suchen und habe dieses Beispiel mit anderen Projekten kombiniert. Warum ich FLTK gewählt habe: Bei meinen Experimenten mit digitaler Signalverarbeitung brauchte ich ein einfaches Werkzeug zur grafischen Darstellung der Ergebnisse. SDL war mir zu spartanisch. Bei GTK waren fast alle Funktionen, die mir nützlich erschienen, als depricated gebrandmarkt und es wurde auf Cairo verwiesen. Danach sah ich nur noch FLTK und wxWidgets als Alternative. Da FLTK sofort funktioniert hat, bin ich dabei geblieben. Ich denke, meine Probleme haben weniger mit irgendeiner Programmiersprache zu tun, sonder mehr mit meinen begrenzten Kenntnissen über Linux Systemfunktionen und Entwurfsmustern (und wie man diese umsetzt).
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4563
Wohnort: Berlin
|
@Dakuan: Den Einwand zu Qt verstehe ich nicht wirklich. Ja die haben C++ etwas erweitert und einen Präprozessor der diese Erweiterungen in reines C++ übersetzt. Hätte man auch mit Template-Magie machen können, aber schöner wäre das wahrscheinlich nicht geworden. Wenn das irgendwer von den vielen Leuten die Qt verwenden als Problem angesehen hätte, gäbe es ziemlich sicher ein Projekt, das den Präprozessor durch Template-Magie ersetzt. Dann halt Gtk+ statt Qt. Die gtkmm-Entwickler haben bei der C++-Anbindung mit Templates gearbeitet. Die STL ist keine zusätzliche Abhängigkeit, die gehört zu C++ dazu. Das war zu Anfangszeiten von FLTK noch eine externe Abhängigkeit, aber das ist schon sehr lange her. Warum hast Du Cairo dann nicht verwendet? Das ist ja keine externe Abhängigkeit — Gtk 3 macht alles was 2D ist damit, also die ganze Oberfläche. Darum sind die alten Zeichenfunktionen auch deprecated, denn die gibt's schlicht nicht mehr, beziehungsweise sind es einfach nur die alten Aufrufe, die intern dann die entsprechenden Aufrufe von Cairo machen. Den Umweg kann/sollte man sich dann halt sparen. Bei den Linux-Systemfunktionen fehlen Dir glaube ich die Kenntnisse nur in so weit, als dass Du vermutest man kann das was Du da vor dem Umbenennen sicherstellen willst, alles vorher abklären. Ich würde sagen: kann man nicht. Und man muss sowieso auf Fehler beim umbenennen reagieren, denn das was man vor der Aktion geprüft hat, muss kurze Zeit später, wenn man die Aktion dann tatsächlich durchführt, ja schon nicht mehr gelten. Ich habe so ein bisschen das Gefühl du verzettelst Dich in Details die man später noch ergänzen kann. Ich würde erst einmal das umbennenen implementieren, mit sinnvoller Behandlung von dem was bei der tatsächlichen Aktion so schief gehen kann. Denn das braucht man auf jeden Fall. Und wenn das läuft, kann man sich daran machen Prüfungen einzubauen welche das eine oder andere Problem vorher schon erkennen und dem Benutzer mitteilen können. Ich habe das FLTK-Programm, das Du als Ausgang verwendet hast, mal nach Qt4 ”übersetzt”. Da gibt es freundlicherweise schon ein QListWidget , das einen IconMode hat. Das selbst berechnen von den Positionen entfällt da also. ☺ test.pro:
| QT += core gui
SOURCES += main.cpp
HEADERS += main.h
|
main.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | #ifndef MAIN_H
#define MAIN_H
#include <QtGui>
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private slots:
void showThumbnailInfo(QListWidgetItem *);
};
#endif // MAIN_H
|
main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 | #include <QtGui>
#include "main.h"
static const char *CAT_XPM[] = {
"50 34 4 1",
" c black",
"o c #ff9900",
"@ c #ffffff",
"# c None",
"##################################################",
"### ############################## ####",
"### ooooo ########################### ooooo ####",
"### oo oo ######################### oo oo ####",
"### oo oo ####################### oo oo ####",
"### oo oo ##################### oo oo ####",
"### oo oo ################### oo oo ####",
"### oo oo oo oo ####",
"### oo oo ooooooooooooooo oo oo ####",
"### oo ooooooooooooooooooooo oo ####",
"### oo ooooooooooooooooooooooooooo ooo ####",
"#### oo ooooooo ooooooooooooo ooooooo oo #####",
"#### oo oooooooo ooooooooooooo oooooooo oo #####",
"##### oo oooooooo ooooooooooooo oooooooo oo ######",
"##### o ooooooooooooooooooooooooooooooo o ######",
"###### ooooooooooooooooooooooooooooooooooo #######",
"##### ooooooooo ooooooooo ooooooooo ######",
"##### oooooooo @@@ ooooooo @@@ oooooooo ######",
"##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######",
"##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######",
"##### oooooooo @@@ ooooooo @@@ oooooooo ######",
"##### ooooooooo ooooooooo ooooooooo ######",
"###### oooooooooooooo oooooooooooooo #######",
"###### oooooooo@@@@@@@ @@@@@@@oooooooo #######",
"###### ooooooo@@@@@@@@@ @@@@@@@@@ooooooo #######",
"####### ooooo@@@@@@@@@@@ @@@@@@@@@@@ooooo ########",
"######### oo@@@@@@@@@@@@ @@@@@@@@@@@@oo ##########",
"########## o@@@@@@ @@@@@ @@@@@ @@@@@@o ###########",
"########### @@@@@@@ @ @@@@@@@ ############",
"############ @@@@@@@@@@@@@@@@@@@@@ #############",
"############## @@@@@@@@@@@@@@@@@ ###############",
"################ @@@@@@@@@ #################",
"#################### #####################",
"##################################################"
};
Window::Window()
{
QListWidget *thumbnails = new QListWidget(this);
thumbnails->setViewMode(thumbnails->IconMode);
thumbnails->setMovement(thumbnails->Static);
thumbnails->setResizeMode(thumbnails->Adjust);
QPixmap cat_pixmap(CAT_XPM);
QSize size = cat_pixmap.size();
size.rheight() += 20; // Leave some space for text under the item.
thumbnails->setIconSize(size);
thumbnails->setGridSize(size + QSize(30, 30));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(thumbnails);
QIcon cat_icon;
cat_icon.addPixmap(cat_pixmap);
for (int i = 0; i < 40; i++) {
new QListWidgetItem(cat_icon, QString().sprintf("%04d", i), thumbnails);
}
connect(thumbnails,
SIGNAL(itemClicked(QListWidgetItem*)),
SLOT(showThumbnailInfo(QListWidgetItem*)));
}
void Window::showThumbnailInfo(QListWidgetItem *item)
{
QMessageBox::information(this,
"Title",
QString("Thumbnail '%1' clicked.").arg(item->text()));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window *window = new Window();
window->show();
return app.exec();
}
|
Übersetzen kann man das mit qmake-qt4 && make . Nun möchte man ja aber nicht immer diesen ganzen Code schreiben um die GUI-Elemente zu erstellen und zu layouten und die ganzen Grundeinstellungen zu machen. Von einem GUI-Rahmenwerk erwarte ich das es dafür eine GUI-Anwendung gibt mit der man sich den statischen Teil der Oberfläche zusammenklicken kann, das als Datendatei speichern kann, die dann im Programm dynamisch geladen werden kann. Wenn ich das für die GUI in dem C++-Beispiel mache, die Datendatei dann aber mit Python verwende, sieht das Programm nur noch so aus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 | #!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
import sys
from PyQt4 import uic
from PyQt4.QtCore import QSize
from PyQt4.QtGui import (
QApplication, QIcon, QListWidgetItem, QMessageBox, QPixmap,
)
CAT_XPM = [
'50 34 4 1',
' c black',
'o c #ff9900',
'@ c #ffffff',
'# c None',
'##################################################',
'### ############################## ####',
'### ooooo ########################### ooooo ####',
'### oo oo ######################### oo oo ####',
'### oo oo ####################### oo oo ####',
'### oo oo ##################### oo oo ####',
'### oo oo ################### oo oo ####',
'### oo oo oo oo ####',
'### oo oo ooooooooooooooo oo oo ####',
'### oo ooooooooooooooooooooo oo ####',
'### oo ooooooooooooooooooooooooooo ooo ####',
'#### oo ooooooo ooooooooooooo ooooooo oo #####',
'#### oo oooooooo ooooooooooooo oooooooo oo #####',
'##### oo oooooooo ooooooooooooo oooooooo oo ######',
'##### o ooooooooooooooooooooooooooooooo o ######',
'###### ooooooooooooooooooooooooooooooooooo #######',
'##### ooooooooo ooooooooo ooooooooo ######',
'##### oooooooo @@@ ooooooo @@@ oooooooo ######',
'##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######',
'##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######',
'##### oooooooo @@@ ooooooo @@@ oooooooo ######',
'##### ooooooooo ooooooooo ooooooooo ######',
'###### oooooooooooooo oooooooooooooo #######',
'###### oooooooo@@@@@@@ @@@@@@@oooooooo #######',
'###### ooooooo@@@@@@@@@ @@@@@@@@@ooooooo #######',
'####### ooooo@@@@@@@@@@@ @@@@@@@@@@@ooooo ########',
'######### oo@@@@@@@@@@@@ @@@@@@@@@@@@oo ##########',
'########## o@@@@@@ @@@@@ @@@@@ @@@@@@o ###########',
'########### @@@@@@@ @ @@@@@@@ ############',
'############ @@@@@@@@@@@@@@@@@@@@@ #############',
'############## @@@@@@@@@@@@@@@@@ ###############',
'################ @@@@@@@@@ #################',
'#################### #####################',
'##################################################',
]
def main():
application = QApplication(sys.argv)
window = uic.loadUi('test.ui')
cat_pixmap = QPixmap(CAT_XPM)
# Leave some space for text under the item.
size = cat_pixmap.size() + QSize(0, 20)
window.thumbnails.setIconSize(size)
window.thumbnails.setGridSize(size + QSize(30, 30))
cat_icon = QIcon(cat_pixmap)
for i in xrange(40):
QListWidgetItem(cat_icon, format(i, '04d'), window.thumbnails)
window.thumbnails.itemClicked.connect(
lambda item: QMessageBox.information(
window,
'Title',
"Thumbnail '{}' clicked.".format(item.text()),
)
)
window.show()
sys.exit(application.exec_())
if __name__ == '__main__':
main()
|
Eine Funktion mit etwas mehr als 20 Zeilen.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Warum hast Du Cairo dann nicht verwendet?
Es ist mir damals an einem Wochenende nicht gelungen, zu verstehen, wie das funktioniert. Ich wollte einfach nur von einem Signal eine FFT und einen Amplitudenverlauf in Echtzeit darstellen. Am einfachsten geht das, wenn man eine Funktion hat, die einfach nur einen Pixelpuffer auf den Bildschirm zaubert. Das hatte ich bei Cairo nicht gefunden.Und die Tutorials machten alle den Eindruck, als hätte sie jemand geschrieben, der sich die Hose mit der Kneifzange anzieht. Bei FLTK gibt bei den mitgelieferten Programmen sogar Beispiele, die das demonstrieren. Kann man fast 1:1 abschreiben.
Ich habe das FLTK-Programm, das Du als Ausgang verwendet hast, mal nach Qt4 ”übersetzt”.
Wow, vielleicht bekomme ich damit ja doch irgendwann noch einen Draht zu Qt. Es gab ja in der Geschichte schonmal einen Fall, wo es hilfreich war, einen Sachverhalt in mehreren Sprachen vorliegen zu haben. Aber das Beispiel war nur ein Baustein. Den habe ich inzwischen heftig modifiziert und mit anderen kombiniert (siehe Anhang). Zum eigentlichen Problem, ich werde rename() erstmal machen lassen, und anhand des Fehlercodes entscheiden, ob ein zweiter Versuch mit Kopieren und Löschen erfolgversprechend sein könnte.
Von einem GUI-Rahmenwerk erwarte ich das es dafür eine GUI-Anwendung gibt mit der man sich den statischen Teil der Oberfläche zusammenklicken kann, ...
Bei FLTK heißt das FLUID. P.s. Vielleicht sollte ich noch folgendes anmerken. Als ich damals nach einen GUI Toolkit gesucht hatte, hatte ich noch keine Ahnung von C++. Da kam also gleich 2 Mal Neuland auf mich zu.
- Bilder
|