简体   繁体   中英

Reading a file from user input c++

I have been trying to get this to work for an hour now and I know it can't be that difficult a fix. Every time I enter the file.txt name it comes up as invalid file. I tried moving the files to the same directory as the.cpp file and everything but I just cant get it to read. Help would be appreciated.

#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>


using namespace std;
const int SIZE = 20;

void readIntFile(ifstream& x, int intArray[], int size, int &length);
void printValues(int intArray[], int& length);
char getSentinel();

int main()
{
    
    ifstream inputStream;
    const int size = SIZE;
    string fileName;
    int length = 0;
    bool isEmpty = false;
    int intArray[size];
    char sentinel = 'y';
    while (sentinel == 'y' || sentinel == 'Y')
    {
        cout << "Please enter the name of the file: ";
        cin >> fileName;
        inputStream.open(fileName);
        if (inputStream.bad() || inputStream.fail())
        {
            cout << "Error, <" << fileName << "> is Invalid File Name.";
        }
        if (fileName.empty())
        {
            isEmpty = true;
        }
        if (isEmpty == true)
        {
            cout << "Error <" << fileName << "> has no data.";
        }
        if (inputStream.good() && isEmpty == false)
        {
            readIntFile(inputStream, intArray, size, length);
            printValues(intArray, length);
            inputStream.close();
        }
        sentinel = getSentinel();
    }




    return 0;
}

void readIntFile(ifstream& x, int intArray[], int size, int& length)
{
    int count = 0;
    int arrayLocation = -1;
    int fileInputValue = 0;
    x >> fileInputValue;
    while (!x.eof())
    {
        count ++;
        if (count > SIZE)
        {
            cout << "The file has more than <" << SIZE << "> values." << endl;
            break;
        }
        else
        {
            arrayLocation ++;
            intArray[count] = fileInputValue;
            x >> fileInputValue;

        }
    }

}

void printValues(int intArray[], int& length)
{
    assert(length > 0);
    cout << "<" << length << "> values processed from the file. The values are: ";
    for (int i=0; i <= length; i++)
    {
        cout << intArray[i] << ", ";
    }

}

char getSentinel()
{
    char userInput = 'n';
    bool inputCheck = false;
    cout << "Do you wish to process another file (y/n)?" << endl;
    cin >> userInput;
    do
    {
        if (userInput == 'y' || userInput == 'Y' || userInput == 'n' || userInput == 'N')
        {
            inputCheck = true;
        }
        else
        {
            cout << "Invalid response: <" << userInput << ">" << endl;
            cout << "Do you wish to process another file (y/n)?" << endl;
            cin >> userInput;
        }
    } while (!inputCheck);


    return userInput;
}

Your basic problem is in function

void readIntFile(ifstream& x, int intArray[], int size, int& length)

You do not set the output variable length . And you use the wrong index value for your array. Please check.

Additionally there are many other problems in your code.

I will now paste your code, amended with my comments comments, where problems are or where things should be improved.

Please see:

#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>


using namespace std;    // Should never be used. Always use fully qualified names
const int SIZE = 20;    // Please use constexpr

// Do not use C-Style function prototypes. Put main at the bottom
// Do not use C-Style Arrays
// In C++ (C-Style-)Arrays are different. You actually do not pass an array to your function
// but a decyed pointer. You can pass an array by pointer or by reference, but this has a different syntax
void readIntFile(ifstream& x, int intArray[], int size, int &length);
void printValues(int intArray[], int& length);
char getSentinel();

int main()
{
    // All variables shall be initialized at the point of defintion
    ifstream inputStream;   // You should define variables just before you need then
    const int size = SIZE;  // This is code duplication. And constexpr should be used
    string fileName;
    int length = 0;
    bool isEmpty = false;
    int intArray[size];   // C-Style Arrays should not be used. Use std::array or best, std::vector
    char sentinel = 'y';  // You could use universal initializer syntax with braced initializer
    while (sentinel == 'y' || sentinel == 'Y')
    {
        cout << "Please enter the name of the file: ";
        cin >> fileName;
        inputStream.open(fileName);   // The constructor can open the file for you
        if (inputStream.bad() || inputStream.fail()) // This is too complicated
        {
            cout << "Error, <" << fileName << "> is Invalid File Name.";
        }
        if (fileName.empty())  // Check is too late and not necessary
        {
            isEmpty = true;
        }
        if (isEmpty == true)
        {
            cout << "Error <" << fileName << "> has no data.";
        }
        if (inputStream.good() && isEmpty == false)
        {
            readIntFile(inputStream, intArray, size, length);
            printValues(intArray, length);
            inputStream.close();  // Destructor will clsoe the file for you
        }
        sentinel = getSentinel();
    }
    return 0;
}

// Not optimal function prototype
void readIntFile(ifstream& x, int intArray[], int size, int& length)
{
    // the whole design / logic is very strange
    int count = 0; 
    int arrayLocation = -1; // More then strange. Shows that this is a bad design
    int fileInputValue = 0;
    x >> fileInputValue;
    while (!x.eof())        // Bad or even wrong design
    {
        count ++;   // Wrong. See below. array will be filled with starting with index one
        if (count > SIZE)
        {
            cout << "The file has more than <" << SIZE << "> values." << endl;
            break;
        }
        else
        {
            arrayLocation ++;   // This variable is not used
            intArray[count] = fileInputValue;
            x >> fileInputValue;

        }
    }
    // Nobody will set the length variable
}

void printValues(int intArray[], int& length)
{
    assert(length > 0); // Basically OK, but no necessary here. Cannoz happen
    cout << "<" << length << "> values processed from the file. The values are: ";
    for (int i=0; i <= length; i++)
    {
        cout << intArray[i] << ", ";
    }
    // There is now newline character used anywhere
}

// Very complicated
char getSentinel()
{
    char userInput = 'n';
    bool inputCheck = false;
    cout << "Do you wish to process another file (y/n)?" << endl;
    cin >> userInput;
    do
    {
        if (userInput == 'y' || userInput == 'Y' || userInput == 'n' || userInput == 'N')
        {
            inputCheck = true;
        }
        else
        {
            cout << "Invalid response: <" << userInput << ">" << endl;
            cout << "Do you wish to process another file (y/n)?" << endl;
            cin >> userInput;
        }
    } while (!inputCheck);

    return userInput;
}


Next, I will make your code working, by fixing the biggest problems. I will still follow your programming style.

#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<assert.h>



constexpr int MaxArraySize = 20;
using IntArray = int[MaxArraySize];

void readIntFile(std::ifstream& x, int intArray[], int& length)
{
    length = 0;
    int value{};
    while (x >> value)
    {
        if (length >= MaxArraySize)
        {
            std::cout << "The file has more than <" << MaxArraySize << "> values.\n";
            break;
        }
        else
        {
            intArray[length++] = value;
        }
    }
}

void printValues(int intArray[], int& length)
{
    std::cout << "\n<" << length << "> values processed from the file. The values are: ";
    for (int i=0; i < length; i++)
    {
        std::cout << intArray[i] << ", ";
    }
    std::cout << "\n\n";
}

bool getSentinel()
{
    char userInput{'n'};
    bool valid = false;
    while (not valid)
    {
        std::cout << "\n\nDo you wish to process another file (y/n)?\n";
   
        std::cin >> userInput;
        if (userInput != 'y' && userInput != 'Y' && userInput != 'n' && userInput != 'N')
        {
            std::cout << "Invalid response: <" << userInput << ">\n\n";
        }
        else {
            valid = true;
        }
    }
    return ( userInput=='y' || userInput=='Y');
}

int main()
{
    
    int intArray[MaxArraySize];
    
    bool sentinel = true;
    while (sentinel)
    {
        std::cout << "Please enter the name of the file: ";
        
        std::string fileName{};
        std::cin >> fileName;
        if (fileName.empty())
        {
            std::cout << "Error <" << fileName << "> has no data.\n\n";
        }
        else {
            std::ifstream inputStream(fileName);
            if (!inputStream)
            {
                std::cout << "Error, <" << fileName << "> is Invalid File Name.\n\n";
            }
            else 
            {
                int length = 0;
                readIntFile(inputStream, intArray, length);
                printValues(intArray, length);
            }
        }
        sentinel = getSentinel();
    }
    return 0;
}

and, in the end, because we are in a C++ site here, I will show (one of many possible) a more advanced C++ solution.

This is just for information and to grab some ideas for the future

#include<iostream>
#include<iomanip>
#include<fstream>
#include<string>
#include<vector>
#include<algorithm>
#include<iterator>
#include<initializer_list>


// Some aliases for easier reading and saving typing work
using DataType = int;
using Vector = std::vector<DataType>;

// Define an "in" operator
struct in {
    in(const std::initializer_list<char>& il) : ref(il) {}
    const std::initializer_list<char>& ref;
};
bool operator,(const char& lhs, const in& rhs) {
    return std::find(rhs.ref.begin(), rhs.ref.end(), lhs) != rhs.ref.end();
}


int main() {
    
    // As long as the user wants to read files
    for (bool userWantsToContinue{true}; userWantsToContinue;) {
        
        std::cout << "\nPlease enter a valid filename:  ";
        if (std::string filename{}; std::cin >> filename) {
            
            // Open the file for reading and check, it it is open
            if (std::ifstream inputStream{filename}; inputStream) {
                
                // Read all data from the file    
                Vector data(std::istream_iterator<DataType>(inputStream), {});
                
                // Now show result to user
                std::cout << "\nRead values are:\n";
                std::copy(data.begin(), data.end(), std::ostream_iterator<DataType>(std::cout, " "));
                
            }
            else std::cerr << "\nError: Could not open file '" << filename << "' for reading\n\n";
        }
        else std::cerr << "\nError: Problem with filename input\n\n";
        
        // Ask, if the user wants to continue
        bool validInput{false};
        while (not validInput) {
            std::cout << "\n\nDo you want to read more files? Please enter 'y' or 'n'  ";
            if (char selection{}; (std::cin >> selection) && (selection, in{'y','Y','n','N',}) ) {
                validInput = true;
                userWantsToContinue = (selection, in{'y','Y'});
            }
            else {
                std::cout << "\n\nInvalid input, please retry\n\n";
            }
        }
    }
    return 0;
}
  • Try using an full absolute filename, not a relative one.

  • And replace cin >> fileName; with std::getline(std::cin, fileName); Otherwise, it will easily break. The getline version is much more robust.

  • If this was not enough, read the answer of: How do I get the directory that a program is running from? and do the checks suited for your system to find out your "working directory". This is the place where you input file must be, if you don't use absolute paths.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM