NYCJUG/2012-02-14/compareReadingFilesInC(2b2b)AndJ
There is a considerable amount of coding overhead associated with the basic task of reading a file in C++. By comparison, the J code is trivially simple.
Compare Simple C++ File Readers
Both of these versions are Microsoft Visual Studio C++ “Console CLR” applications. The first reads a text file (from http://msdn.microsoft.com/en-us/library/y52yxde8.aspx), the second a binary file containing four integers.
// readDataFileCLR.cpp : main project file. #include "stdafx.h" using namespace System; using namespace System::IO; using namespace System::Collections; int main(array<System::String ^> ^args) { String^ fileName = "textfile.txt"; try { Console::WriteLine("Trying to open file {0}...", fileName); StreamReader^ din = File::OpenText(fileName); String^ str; int count = 0; while ((str = din->ReadLine()) != nullptr) { count++; Console::WriteLine("Line {0}: {1}", count, str ); } } catch (Exception^ e) { if (dynamic_cast<FileNotFoundException^>(e)) Console::WriteLine("File '{0}' not found", fileName); else Console::WriteLine("Problem reading file '{0}'", fileName); } return 0; }
This reads a binary file (from http://msdn.microsoft.com/en-us/library/3f3t7tke.aspx):
// binary_readCLR.cpp : main project file. // compile with: /clr #include "stdafx.h" #using<system.dll> using namespace System; using namespace System::IO; int main() { String^ fileName = "C:\\amisc\\data.bin"; try { FileStream^ fs = gcnew FileStream(fileName, FileMode::Open); BinaryReader^ br = gcnew BinaryReader(fs); Console::WriteLine("Contents of {0}:", fileName); while (br->BaseStream->Position < br->BaseStream->Length) Console::WriteLine(br->ReadInt32().ToString()); fs->Close( ); } catch (Exception^ e) { if (dynamic_cast<FileNotFoundException^>(e)) Console::WriteLine("File '{0}' not found", fileName); else Console::WriteLine("Exception: ({0})", e); return -1; } return 0; }
Read Text File with J
Doing the same thing in J is far simpler. The following two examples leave out the checks for the existence and the readability of the file that the C code has since the J code is typically used interactively. If we wished to more exactly emulate the C code, the checks would require only a line or two more.
text=. fread 'textfile.txt' $text NB. Shape - too big to show all right now... 807 >3{.<;._2 text-.CR NB. Look at first 3 lines only. // Readdatafileclr.Cpp : Main Project File. #Include "Stdafx.H"
Read Binary File with J
Notice that we do exactly the same thing as we did reading a text file – why wouldn’t we? It’s one less variation to remember. A copy of this file is File:Databin.txt; you may want to rename it to "data.bin".
bindat=. fread 'C:\amisc\data.bin' $bindat NB. Only 16 bytes = 4 integers. 16 bindat NB. Binary doesn’t display nicely, [1] ---- ' NB. so let’s convert the bytes into integers. cvtIntFromBytes=: 256 #. [: |. a. i. ] cvtIntFromBytes _4{.bindat NB. Works for last 4 and 10000 cvtIntFromBytes 4{.bindat NB. for first 4, so apply it to whole array, 1 cvtIntFromBytes &> _4<\bindat NB. to non-overlapping windows of 4 bytes. 1 2 3 10000
Here’s the cover function fread we used above. It uses one of the J foreign conjunctions “1!:1” if file is identified by a handle (file number) or “1!:11” if identified by name.
fread=: 3 : 0 if. 1 = #y=. boxopen y do. 1!:1 :: _1: fboxname y else. 1!:11 :: _1: (fboxname {.y),{:y end. : x freads y )