Need to list all files in a directory on AIX - aix

Have a program that needs to list all the files in a directory on AIX.
Have successfully done this on Windows:-
hFind = FindFirstFile(szDir, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
fprintf(stderr,"Can not scan for files.\n");
goto MOD_EXIT;
}
do
{
if (! (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
printf("File:%s\n",ffd.cFileName);
}
}
while (FindNextFile(hFind, &ffd) != 0);
and on Linux:-
d = opendir(szDir);
if (!d)
{
fprintf(stderr,"Can not open directory '%s'.\n",szDir);
goto MOD_EXIT;
}
while(dir = readdir(d))
{
if (dir->d_type != DT_DIR)
{
printf("File:%s\n",dir->d_name);
}
}
closedir(d);
readdir appears to exist on AIX, but from the manual it would appear it only returns directories not files. The field d_type does not exist in the dirent structure.

When readdir() refers to directory entries it means entries in the directory, not subdirectories of the directory. So you can get all the names from there.
To discover if they are files or directories, the portable / reliable way is to to stat() the result. There are standard macros to test the st_mode returned in the stat buffer (e.g. S_ISDIR)

Related

How should I bundle a library of text files with my module?

I have the following structure in the resources directory in a module I'm building:
resources
|-- examples
|-- Arrays
| |-- file
|-- Lists
|-- file1
|-- file2
I have the following code to collect and process these files:
use v6.d;
unit module Doc::Examples::Resources;
class Resource {
has Str $.name;
has Resource #.resources;
has Resource %.resource-index;
method resource-names() {
#.resources>>.name.sort
}
method list-resources() {
self.resource-names>>.say;
}
method is-resource(Str:D $lesson) {
$lesson ~~ any self.resource-names;
}
method get-resource(Str:D $lesson) {
if !self.is-resource($lesson) {
say "Sorry, that lesson does not exist.";
return;
}
return %.resource-index{$lesson};
}
}
class Lesson is Resource {
use Doc::Parser;
use Doc::Subroutines;
has IO $.file;
method new(IO:D :$file) {
my $name = $file.basename;
self.bless(:$name, :$file)
}
method parse() {
my #parsed = parse-file $.file.path;
die "Failed parse examples from $.file" if #parsed.^name eq 'Any';
for #parsed -> $section {
my $heading = $section<meta>[0] || '';
my $intro = $section<meta>[1] || '';
say $heading.uc ~ "\n" if $heading && !$intro;
say $heading.uc if $heading && $intro;
say $intro ~ "\n" if $intro;
for $section<code>.Array {
die "Failed parse examples from $.file, check it's syntax." if $_.^name eq 'Any';
das |$_>>.trim;
}
}
}
}
class Topic is Resource {
method new(IO:D :$dir) {
my $files = dir $?DISTRIBUTION.content("$dir");
my #lessons;
my $name = $dir.basename;
my %lesson-index;
for $files.Array -> $file {
my $lesson = Lesson.new(:$file);
push #lessons, $lesson;
%lesson-index{$lesson.name} = $lesson;
}
self.bless(:$name, resources => #lessons, resource-index => %lesson-index);
}
}
class LocalResources is Resource is export {
method new() {
my $dirs = dir $?DISTRIBUTION.content('resources/examples');
my #resources;
my %resource-index;
for $dirs.Array -> $dir {
my $t = Topic.new(:$dir);
push #resources, $t;
%resource-index{$t.name} = $t;
}
self.bless(:#resources, :%resource-index)
}
method list-lessons(Str:D $topic) {
self.get-resource($topic).list-lessons;
}
method parse-lesson(Str:D $topic, Str:D $lesson) {
self.get-resource($topic).get-resource($lesson).parse;
}
}
It works. However, I'm told that this is not reliable and there there is no guarantee that lines like my $files = dir $?DISTRIBUTION.content("$dir"); will work after the module is installed or will continue to work into the future.
So what are better options for bundling a library of text files with my module that can be accessed and found by the module?
Files under the resources directory will always be available as keys to the %?RESOURCES compile-time variable if you declare them in the META6.json file this way:
"resources": [
"examples/Array/file",
]
and so on.
I've settled on a solution. As pointed out by jjmerelo, the META6.json file contains a list of resources and, if you use the comma IDE, the list of resources is automatically generated for you.
From within the module's code, the list of resources can be accessed via the $?DISTRIBUTION variable like so:
my #resources = $?DISTRIBUTION.meta<resources>
From here, I can build up my list of resources.
One note on something I discovered: the $?DISTRIBUTION variable is not accessible from a test script. It has to be placed inside a module in the lib directory of the distribution and exported.

Where and how do I make another folder to put text files so they work when I export?

I have a folder with my text files that can read and write and work in eclipse. But, when I export to jar, it fails because the files are not found, meaning they are not exported and I don't know how to make eclipse do that. I'm sure the solution is out there, but I don't know exactly what I'm searching for. Do I make a relative directory and how? Or another source folder? What exactly do I need to do?
This shows I have a folder called conf where my files are stored but it is not there on export.
Scanner in = new Scanner(new FileReader("conf/Admins.txt"));
FileWriter out = new FileWriter("conf/CurrentUser.txt");
int id = 0;
String name = "";
String pass = "";
boolean found = false;
while(in.hasNext()) {
id = in.nextInt();
name = in.next();
pass = in.next();
if(id == userID) {
out.write(id + " " + name + " " + pass + "\n");
found = true;
break;
}
}
All I had to do was once exported, put my conf file in the same place as the exported jar file. I don't know if, theres a better way but this is a win for me.

Correct usage of SetRootType in FlatBuffers

I'm trying to set a new custom root before parsing a JSon into a structure via flatbuffers.
The Corresponding FSB has a root_type already and I want to override it only to be able to parse it into a struct once.
The SetRootType("NonRootStructInFbsT") fails
The documentation of the API says, this can be used to override the current root which is exactly what I want to do.
std::string schemaText;
std::string schemaFile("MySchema.fbs");
if(not flatbuffers::FileExists(schemaFile.c_str())) {
error("Schema file inaccessible: ", schemaFile);
return nullptr;
}
if(not flatbuffers::LoadFile(schemaFile.c_str(), false, &schemaText)) {
error(TAG, "Failed to load schema file: ", schemaFile);
return nullptr;
}
info("Read schema file: ", schemaText.size(), schemaText);
flatbuffers::Parser parser;
if(not parser.SetRootType("NonRootStructInFbsT")) {
error("Unable to set root type: ", customRoot);
return nullptr;
}
info("Set the root type: ", customRoot);
I always get the error message
Unable to set root type: NonRootStructInFbsT
The root of a FlatBuffer can only be a table, so root_type and SetRootType will reject names of anything else, like a struct or a union.
Furthermore, the fact that the name ends in T appears to refer to an "object API" type. These are names purely in the generated code, you need to supply names as they are in the schema.
The posted code lacks call of flatbuffers::Parser::Parse with schema contents. Your code:
std::string schemaText;
std::string schemaFile("MySchema.fbs");
if(not flatbuffers::FileExists(schemaFile.c_str())) {
error("Schema file inaccessible: ", schemaFile);
return nullptr;
}
if(not flatbuffers::LoadFile(schemaFile.c_str(), false, &schemaText)) {
error(TAG, "Failed to load schema file: ", schemaFile);
return nullptr;
}
info("Read schema file: ", schemaText.size(), schemaText);
flatbuffers::Parser parser;
It is all OK, but here we have contents of schema file in schemaText and empty parser with default options. Too early to set root types. We should read the schema to parser with something like:
if(not parser.Parse(schemaText)) {
error(TAG, "Defective schema: ", parser.error_);
return nullptr;
}
After that if we reached here we have parser with schema and so in that schema we can chose also root type:
if(not parser.SetRootType("NonRootStructInFbsT")) {
error("Unable to set root type: ", customRoot);
return nullptr;
}
info("Set the root type: ", customRoot);
Note that parser.error_ is quite informative about any errors you face during parser usage.

Search and List all files from directory/subdirectories into ListBox

Ok solved a bit my old problem thx to #sircodesalot
Public Sub AppendFilesFromDirectory(ByVal path As DirectoryInfo, ByVal files As List(Of FileInfo))
For Each file As FileInfo In CurrentFolder.GetFiles()
files.Add(file)
Next
For Each subfolder As DirectoryInfo In CurrentFolder.GetDirectories()
AppendFilesFromDirectory(subfolder, files)
Next
End Sub
Dim files As New List(Of FileInfo)
AppendFilesFromDirectory(New DirectoryInfo(FolderBrowserDialog1.SelectedPath), files)
For Each file As FileInfo In files
ListBox1.Items.Add(file.FullName)
Next
And it works well for folders which have subfolders in it, but if a folder has only files then it becomes a loop adding continuously the file to myList.
Any suggestions how to avoid it? #sircodesalot kindly tried to explain me but I'm not able to do wathever I try..
Help is really appreciated!
First get your head around a simple recursive function like factorial. For example:
int factorial(int number) {
if (number < 1)
return 1;
else
return factorial(number - 1) * number;
}
Basically, if we want to calculate factorial(5), then it's just:
factorial(5) * factorial(4) * factorial (3) * factorial(2) * factorial(1)
or more abstractly:
factorial(n) * factorial(n - 1) * factorial (n - 2) * ... * factorial (1)
So we make the function call itself with a diminishing value to compute the result.
The same applies do your problem above. If we want to get all the sub directories, then all we have to do is:
(1) List all the files in the current folder
(2) For the files that are directories, repeat step one.
In other words:
List<Folder> readAllFiles() {
List<Folder> folders = new List<Folder>();
readAllFilesRecursively("C:/", folders);
}
List<Folder> readAllFilesRecursively(String directory, List<Folder> folders) {
Folder currentDirectory = castTheStringToADirectorySomehow(directory);
// Add the current folder to the list.
folders.add(currentDirectory);
// ** HERE IS WHAT YOU'RE MISSING ** //
// Re-call the same function on the sub folder, passing in our list
// so that the subfolder items can be added to the list.
foreach (Folder subfolder in currentDirectory.subFolders()) {
readAllFilesRecursively(subFolder.pathString(), folders);
}
// Return the folder list.
return folders;
}
Edit:
So this works for me, but you'll have to change it to VB obviously. Also, I'm on a mac so you'll notice that the path format is a little different:
class Program {
public static void Main() {
List<FileInfo> files = new List<FileInfo> ();
AppendFilesFromDirectory (new DirectoryInfo("/Users/sircodesalot/Desktop/Dev"), files);
foreach (FileInfo file in files) {
Console.WriteLine (file.FullName);
}
}
public static void AppendFilesFromDirectory(DirectoryInfo currentFolder, List<FileInfo> files) {
foreach (FileInfo file in currentFolder.GetFiles()) {
files.Add(file);
}
// This if statement is unneccesary, but I'll add it for clarity
// to explain the concept of a base case. We don't really need it though
// since the 'foreach' statement won't execute if there aren't any items.
if (currentFolder.GetDirectories().Count() > 0) {
// Process the subfolders
foreach (DirectoryInfo subfolder in currentFolder.GetDirectories()) {
AppendFilesFromDirectory (subfolder, files);
}
}
}
}

How do I read multiple files after click opened in OpenFileDialog?

I have set a multiselect function in my code to allow me to open multiple files which is in ".txt" forms. And here is the problem, how am I going to read all these selected files after it opened through OpenFileDialog? The following codes and at the "for each" line, when I use System::Diagnostics::Debug, it shows only the data from a file, while data of other files were missing. How should I modify the code after the "for each"? Can anyone provide some suggestions or advice? The files selected are as 1_1.txt, 2_1.txt, 3_1.txt. Appreciate your reply and Thanks in advance.
Here is my written code,
Stream^ myStream;
OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;
openFileDialog1->InitialDirectory = "c:\\";
openFileDialog1->Title = "open captured file";
openFileDialog1->Filter = "CP files (*.cp)|*.cp|All files (*.*)|*.*|txt files (*.txt)|*.txt";
openFileDialog1->FilterIndex = 2;
openFileDialog1->Multiselect = true;
if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
{
array<String^>^ lines = System::IO::File::ReadAllLines(openFileDialog1->FileName);
for each (String^ line in lines) {
//?????
System::Diagnostics::Debug::WriteLine("",line);
}
}
You need to look at the OpenFileDialog.FileNames property if you allow multiple files to be selected:
if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
{
for each (String^ file in openFileDialog1->FileNames)
{
array<String^>^ lines = System::IO::File::ReadAllLines(file);
for each (String^ line in lines)
{
System::Diagnostics::Debug::WriteLine("",line);
}
}
}
Use the FileNames property.
C# version (should be easy to adapt for C++):
foreach (var file in openFileDialog1.FileNames)
{
foreach (var line in File.ReadAllLines(file)
{
...
}
}
Use openFileDialog1->FileNames. It returns the multiple filenames that you selected
Read here
http://msdn.microsoft.com/en-us/library/system.windows.forms.openfiledialog.multiselect.aspx
its in C# but, it will be easy to extrapolate to C++.